##// END OF EJS Templates
Added test support for better parametric tests and nose fixes....
Fernando Perez -
Show More
@@ -0,0 +1,89 b''
1 """Implementation of the parametric test support for Python 2.x
2 """
3 #-----------------------------------------------------------------------------
4 # Imports
5 #-----------------------------------------------------------------------------
6
7 # Stdlib
8 import unittest
9 from compiler.consts import CO_GENERATOR
10
11 #-----------------------------------------------------------------------------
12 # Classes and functions
13 #-----------------------------------------------------------------------------
14
15 def isgenerator(func):
16 try:
17 return func.func_code.co_flags & CO_GENERATOR != 0
18 except AttributeError:
19 return False
20
21 class ParametricTestCase(unittest.TestCase):
22 """Write parametric tests in normal unittest testcase form.
23
24 Limitations: the last iteration misses printing out a newline when running
25 in verbose mode.
26 """
27 def run_parametric(self, result, testMethod):
28 # But if we have a test generator, we iterate it ourselves
29 testgen = testMethod()
30 while True:
31 try:
32 # Initialize test
33 result.startTest(self)
34
35 # SetUp
36 try:
37 self.setUp()
38 except KeyboardInterrupt:
39 raise
40 except:
41 result.addError(self, self._exc_info())
42 return
43 # Test execution
44 ok = False
45 try:
46 testgen.next()
47 ok = True
48 except StopIteration:
49 # We stop the loop
50 break
51 except self.failureException:
52 result.addFailure(self, self._exc_info())
53 except KeyboardInterrupt:
54 raise
55 except:
56 result.addError(self, self._exc_info())
57 # TearDown
58 try:
59 self.tearDown()
60 except KeyboardInterrupt:
61 raise
62 except:
63 result.addError(self, self._exc_info())
64 ok = False
65 if ok: result.addSuccess(self)
66
67 finally:
68 result.stopTest(self)
69
70 def run(self, result=None):
71 if result is None:
72 result = self.defaultTestResult()
73 testMethod = getattr(self, self._testMethodName)
74 # For normal tests, we just call the base class and return that
75 if isgenerator(testMethod):
76 return self.run_parametric(result, testMethod)
77 else:
78 return super(ParametricTestCase, self).run(result)
79
80
81 def parametric(func):
82 """Decorator to make a simple function into a normal test via unittest."""
83
84 class Tester(ParametricTestCase):
85 test = staticmethod(func)
86
87 Tester.__name__ = func.__name__
88
89 return Tester
@@ -0,0 +1,62 b''
1 """Implementation of the parametric test support for Python 3.x.
2
3 Thanks for the py3 version to Robert Collins, from the Testing in Python
4 mailing list.
5 """
6 #-----------------------------------------------------------------------------
7 # Imports
8 #-----------------------------------------------------------------------------
9
10 # Stdlib
11 import unittest
12 from unittest import TestSuite
13
14 #-----------------------------------------------------------------------------
15 # Classes and functions
16 #-----------------------------------------------------------------------------
17
18
19 def isgenerator(func):
20 return hasattr(func,'_generator')
21
22
23 class IterCallableSuite(TestSuite):
24 def __init__(self, iterator, adapter):
25 self._iter = iterator
26 self._adapter = adapter
27 def __iter__(self):
28 yield self._adapter(self._iter.__next__)
29
30 class ParametricTestCase(unittest.TestCase):
31 """Write parametric tests in normal unittest testcase form.
32
33 Limitations: the last iteration misses printing out a newline when
34 running in verbose mode.
35 """
36
37 def run(self, result=None):
38 testMethod = getattr(self, self._testMethodName)
39 # For normal tests, we just call the base class and return that
40 if isgenerator(testMethod):
41 def adapter(next_test):
42 return unittest.FunctionTestCase(next_test,
43 self.setUp,
44 self.tearDown)
45
46 return IterCallableSuite(testMethod(),adapter).run(result)
47 else:
48 return super(ParametricTestCase, self).run(result)
49
50
51 def parametric(func):
52 """Decorator to make a simple function into a normal test via
53 unittest."""
54 # Hack, until I figure out how to write isgenerator() for python3!!
55 func._generator = True
56
57 class Tester(ParametricTestCase):
58 test = staticmethod(func)
59
60 Tester.__name__ = func.__name__
61
62 return Tester
@@ -0,0 +1,53 b''
1 """Monkeypatch nose to accept any callable as a method.
2
3 By default, nose's ismethod() fails for static methods.
4 Once this is fixed in upstream nose we can disable it.
5
6 Note: merely importing this module causes the monkeypatch to be applied."""
7
8 import unittest
9 import nose.loader
10 from inspect import ismethod, isfunction
11
12 def getTestCaseNames(self, testCaseClass):
13 """Override to select with selector, unless
14 config.getTestCaseNamesCompat is True
15 """
16 if self.config.getTestCaseNamesCompat:
17 return unittest.TestLoader.getTestCaseNames(self, testCaseClass)
18
19 def wanted(attr, cls=testCaseClass, sel=self.selector):
20 item = getattr(cls, attr, None)
21 # MONKEYPATCH: replace this:
22 #if not ismethod(item):
23 # return False
24 # return sel.wantMethod(item)
25 # With:
26 if ismethod(item):
27 return sel.wantMethod(item)
28 # static method or something. If this is a static method, we
29 # can't get the class information, and we have to treat it
30 # as a function. Thus, we will miss things like class
31 # attributes for test selection
32 if isfunction(item):
33 return sel.wantFunction(item)
34 return False
35 # END MONKEYPATCH
36
37 cases = filter(wanted, dir(testCaseClass))
38 for base in testCaseClass.__bases__:
39 for case in self.getTestCaseNames(base):
40 if case not in cases:
41 cases.append(case)
42 # add runTest if nothing else picked
43 if not cases and hasattr(testCaseClass, 'runTest'):
44 cases = ['runTest']
45 if self.sortTestMethodsUsing:
46 cases.sort(self.sortTestMethodsUsing)
47 return cases
48
49
50 ##########################################################################
51 # Apply monkeypatch here
52 nose.loader.TestLoader.getTestCaseNames = getTestCaseNames
53 ##########################################################################
General Comments 0
You need to be logged in to leave comments. Login now