Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 771
Ceasar Bautista Avatar asked Nov 02 '11 16:11

Ceasar Bautista


People also ask

How do I test a function in Python?

First you need to create a test file. Then import the unittest module, define the testing class that inherits from unittest. TestCase, and lastly, write a series of methods to test all the cases of your function's behavior. First, you need to import a unittest and the function you want to test, formatted_name() .


2 Answers

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.

like image 64
Raymond Hettinger Avatar answered Sep 20 '22 07:09

Raymond Hettinger


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)
like image 33
glglgl Avatar answered Sep 21 '22 07:09

glglgl