Ceasar
Ceasar

Reputation: 23073

How to test Python function decorators?

I'm trying to write unit tests to ensure correctness of various decorators I've written. Here's the start of the code I'm trying to write:

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()

While this works decently for the MRU strategy I have above, I plan to write additional strategies, in which case I'll need to decorate with the fib function in different ways. (Recall that because fib calls fib, setting fib2 = memoize(fib) does not memoize intermediate values so that will not work.) What is the correct way to test the other decorators?

Upvotes: 16

Views: 15171

Answers (2)

Raymond Hettinger
Raymond Hettinger

Reputation: 226336

Take a look at the tests in the standard library for examples: http://hg.python.org/cpython/file/3.2/Lib/test/test_functools.py#l553

I usually add some instrumentation to the function being wrapped so that I can monitor the calls.

Instead of memoizing the test function at the module level, I create the memoized function inside the test so that a new one is created for each test and for each decorator variant.

Upvotes: 14

glglgl
glglgl

Reputation: 91049

What about the rather complicated

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

This way you could do

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)

Upvotes: 2

Related Questions