patternpythonMinor
Method injection into TestClass local namespace for automatic generation of Python unittest "test_xxx" methods
Viewed 0 times
localmethodintounittestmethodsgenerationforpythoninjectionautomatic
Problem
I am writing a series of unit tests in Python 3.5
I first wrote the test code with all of my dataset
What I've now got in its place is the following (the code for the entire class can be perused on GitHub):
```
class TestOpanUtilsVectorProjRejAngle(unittest.TestCase):
import numpy as np
from opan.const import OpanEnum
class DType(OpanEnum):
V1 = 'V1'
V2 = 'V2'
PROJ = 'PROJ'
REJ = 'REJ'
ANG = 'ANG'
class VecType(OpanEnum): # Types of vectors
O1 = 'O1' # Both order-one
LOL = 'LOL' # Both large (large on large)
SOS = 'SOS' # Both small (small on small)
LOS = 'LOS' # Large onto small
SOL = 'SOL' # Small onto large
BS = 'BS' # Badly-scaled
class RelType(OpanEnum): # Type of vector relationship
NS = 'NS' # Nonspecific
PAR = 'PAR' # Nearly parallel
unittest, which run the exact same test methods on different datasets. The purpose is to validate proper behavior of each tested function over a range of inputs at different extremes of the likely numerical range of use (large values, small values, badly scaled values, etc.). I would like to construct the TestCase so that it dynamically generates all relevant test_xxx methods for the datasets I've entered. This way it leaves me less room for typos, and avoids the need to write a raft of new functions every time I add a dataset.I first wrote the test code with all of my dataset
dict objects housed in a simple list, and a single test_the_thing function within my unittest.TestCase subclass. test_the_thing would iterate over the list of dict datasets, running the test code on each. Two primary problems arose with this approach:unittestconsiders the entire execution oftest_the_thingto be a single test, and thus I have to search within my datasets to figure out which one failed when the test fails/errors.
- When any given test fails/errors in the middle of the iteration, the remainder of the tests are not run.
What I've now got in its place is the following (the code for the entire class can be perused on GitHub):
```
class TestOpanUtilsVectorProjRejAngle(unittest.TestCase):
import numpy as np
from opan.const import OpanEnum
class DType(OpanEnum):
V1 = 'V1'
V2 = 'V2'
PROJ = 'PROJ'
REJ = 'REJ'
ANG = 'ANG'
class VecType(OpanEnum): # Types of vectors
O1 = 'O1' # Both order-one
LOL = 'LOL' # Both large (large on large)
SOS = 'SOS' # Both small (small on small)
LOS = 'LOS' # Large onto small
SOL = 'SOL' # Small onto large
BS = 'BS' # Badly-scaled
class RelType(OpanEnum): # Type of vector relationship
NS = 'NS' # Nonspecific
PAR = 'PAR' # Nearly parallel
Solution
I think your code is pretty good and you are following good practices with the exception to one (common mistake)
Should be:
This will prevent locals() from being evaluated when not necessary, but that's not even that big of a deal.
check out for another users use of locals https://stackoverflow.com/questions/8028708/dynamically-set-local-variable-in-python
i encourage other developers to review this, as it is a very interesting project.
for name, datadict in data.items():
fxnname = "test_data_{0}".format(name)
fxn = lambda self, n=name, d=datadict: self.template_test_fxn(n, d)
locals().update({fxnname: fxn})Should be:
locals_ = locals()
for name, datadict in data.items():
fxnname = "test_data_{0}".format(name)
fxn = lambda self, n=name, d=datadict: self.template_test_fxn(n, d)
locals_.update({fxnname: fxn})This will prevent locals() from being evaluated when not necessary, but that's not even that big of a deal.
check out for another users use of locals https://stackoverflow.com/questions/8028708/dynamically-set-local-variable-in-python
i encourage other developers to review this, as it is a very interesting project.
Code Snippets
for name, datadict in data.items():
fxnname = "test_data_{0}".format(name)
fxn = lambda self, n=name, d=datadict: self.template_test_fxn(n, d)
locals().update({fxnname: fxn})locals_ = locals()
for name, datadict in data.items():
fxnname = "test_data_{0}".format(name)
fxn = lambda self, n=name, d=datadict: self.template_test_fxn(n, d)
locals_.update({fxnname: fxn})Context
StackExchange Code Review Q#126660, answer score: 2
Revisions (0)
No revisions yet.