how to add tests dynamically to python unittest
python, unit-testing
Solution
The issue is that the loader from unittest runs a dir() on the class before it instantiate it, therefore, it doesn't matter where you create your methods, `__new__`, `__init__`, `setUpClass` etc... the methods get created too late.
There are two ways to work around that, write your own run() method, or use a metaclass. The former means you have to re-write the discovery that's already written in unittest. The metaclass isn't actually that complicated to implement. Here's what I did:
import unittest
import blognodes
class meta_Test_base62(type):
testset = { 0: '0', 10: 'a', 61: 'Z', 62: '10', 3844: '100'}
@classmethod
def __prepare__(mcls, name, bases):
d = dict()
d['testme'] = 5
for b10, b62 in mcls.testset.items():
fname = "test_base62_value_{}".format(b10)
d[fname] = mcls.build_test_base62_values(b10, b62)
fname = "test_int_value_{}".format(b10)
d[fname] = mcls.build_test_int_values(b10, b62)
return d
@classmethod
def build_test_base62_values(cls, b10, b62):
def f(self):
target = blognodes.base62(b10)
self.assertEqual(target.str(), b62)
return f
@classmethod
def build_test_int_values(cls, b10, b62):
def f(self):
target = blognodes.base62(b10)
self.assertEqual(target.int(), b10)
return f
class Test_base62(unittest.TestCase, metaclass=meta_Test_base62):
def test_nothing(self):
self.assertEqual(5, self.testme)
Problem
I'm wanting to set up a `unittest` TestCase where some of the cases are added dynamically. The methods are added as shown from my `test_nothing`, but, `unittest` doesn't take them into account as it runs only one test. It's like I build my `test_xxxx` too late and they are not seen. Is `setUpClass` executed too late in the game? Should I put this in `__init__` build my methods, and then call `super().__init__` ? ``` import unittest import blognodes class Test_base62(unittest.TestCase): testset = { 0: '0', 10: 'a', 61: 'Z', 62: '10', 3844: '100'} @classmethod def setUpClass(cls): cls.testme = 5 print("i am the setUp function") for d, b62 in cls.testset.items(): print("building the first set") cls.build_test_base62_values(d, b62) print("building the second set") cls.build_test_int_values(d, b62) @classmethod def build_test_base62_values(cls, d, b62): def f(cls): target = blognodes.base62(d) cls.assertEqual(target.str(), b62) fname = "test_base62_value_{}".format(d) setattr(cls, fname, f) @classmethod def build_test_int_values(cls, d, b62): def f(cls): target = blognodes.base62(d) cls.assertEqual(target.int(), d) fname = "test_int_value_{}".format(d) setattr(cls, fname, f) def test_nothing(self): print("i'm test nothing") t = dir(self) print(t) self.assertEqual(5, self.testme) ``` Thanks.