如何测试Python函数装饰器?

14 投票
2 回答
14898 浏览
提问于 2025-04-17 05:30

我正在尝试编写单元测试,以确保我写的各种装饰器是正确的。以下是我正在编写的代码的开头:

import unittest

from memoizer import Memoizer
from strategies.mru import MRU


@Memoizer(strategy=MRU(maxsize=10))
def fib(x):
  if x < 2:
    return 1
  else:
    return fib(x-1) + fib(x-2)


class TestMemoizer(unittest.TestCase):

  def test_simple(self):
    self.assertEqual(fib(0), 1)
    self.assertEqual(fib(1), 1)
    self.assertEqual(fib(10), 89)


if __name__ == '__main__':
  unittest.main()

虽然这段代码对于我上面提到的MRU策略效果不错,但我计划编写其他策略,这样我就需要以不同的方式使用fib函数进行装饰。(记住,因为fib函数会调用fib,所以将fib2设置为memoize(fib)并不能记住中间值,所以这样做是行不通的。)那么,测试其他装饰器的正确方法是什么呢?

2 个回答

2

那这个就有点复杂了

def mkfib(strategy):
    @Memoizer(strategy=strategy)
    def fib(x):
      if x < 2:
        return 1
      else:
        return fib(x-1) + fib(x-2)
    return fib

这样你就可以做到

fib1 = mkfib(MRU(maxsize=10))
self.assertEqual(fib1(0), 1)
self.assertEqual(fib1(1), 1)

fib2 = mkfib(MRU(maxsize=10)) # produces another cache
self.assertEqual(fib2(0), 1)
self.assertEqual(fib2(1), 1)
12

你可以看看标准库里的测试示例: http://hg.python.org/cpython/file/3.2/Lib/test/test_functools.py#l553

我通常会在被包装的函数里加一些监控代码,这样我就能观察到函数被调用的情况。

我不是在模块级别上给测试函数加缓存,而是把缓存的函数放在测试内部,这样每个测试和每种装饰器变体都会创建一个新的函数。

撰写回答