如何在 Python (2.7) 单元测试中参数化 setUpClass()
How to parametrize setUpClass() in Python (2.7) unittests
我目前正在实现一种 table,其中包含值之间的插值、边界处理等,并想为其编写单元测试。
有很多可能的场景,例如tables 只能有 one/multiple 行/列和不同的边界条件。所有这些场景中的 table 都应该通过同一组单元测试。
现在我正在为其中一个案例编写基础 class 并从中派生覆盖 setUpClass()
方法。然而,这对于测试所有组合来说是乏味的。
是否可以动态生成 TestCase classes 运行 它们具有不同的参数。
在谷歌搜索问题时,我发现最好的事情是重载 load_tests()
并一个接一个地添加所有测试方法(这意味着在 运行 设置每个测试方法之前设置对象,而不是每个场景一次)。
感谢@jonrsharpe 的提示,我设法做到了。
我的解决方案是动态创建 类,然后使用 load_tests
:
将它们添加到 TestSuite
def create_test_case(testcase_name, scenario_data):
class ScenarioTestCase(BaseTestCase):
@classmethod
def setUpClass(cls):
cls.fillClassVariables(scenario_data)
return_class = ScenarioTestCase
return_class.__name__ = testcase_name #for separating the results
return return_class
def load_tests(loader, tests, pattern):
list_scenario_names = [...]
list_scenario_data = [...]
loader = unittest.TestLoader()
tests = TestSuite()
for scenario_name, scenario_data in zip(list_scenario_names, list_scenario_data):
tests.addTests(loader.loadTestsFromTestCase(
create_test_case(scenario_name, scenario_data)))
return tests
通过这种方式,可以使用不同的参数动态创建测试用例,并在 PyCharm 的测试运行程序选项卡中单独列出。
虽然这有一个公认的答案,但我想记录如何使用 subclassing 来做到这一点,因为我花了很长时间才找到这种解决方案的细节。在我的例子中,目标是使用多种方法的 TestCase class 有一个 class fixture(在文件系统上设置文件以测试 cli 工具),并在参数化中稍微改变一下。
# Inherit from object to not run this abstract class
class TemporaryFolderClassSetup(object):
@classmethod
def setUpClass(cls):
try:
cls._root = tempfile.mkdtemp()
# .. create some files here ...
# allow subclasses to manipulate file tre
cls.prepare_directory(cls._root)
except Exception as e:
cls.tearDownClass()
raise
@classmethod
def tearDownClass(cls):
shutil.rmtree(cls._root)
@classmethod
def prepare_directory(cls, root):
pass
# test methods that will run in each subclass
def testX():
pass
# scenariotest, must inherit from superclass first, before unittest.TestCase)
class ScenarioTests(TemporaryFolderClassSetup, unittest.TestCase):
# ... called by parent class
@classmethod
def prepare_directory(cls, root):
pass
# test only for this scenario
def testY(self):
pass
我目前正在实现一种 table,其中包含值之间的插值、边界处理等,并想为其编写单元测试。
有很多可能的场景,例如tables 只能有 one/multiple 行/列和不同的边界条件。所有这些场景中的 table 都应该通过同一组单元测试。
现在我正在为其中一个案例编写基础 class 并从中派生覆盖 setUpClass()
方法。然而,这对于测试所有组合来说是乏味的。
是否可以动态生成 TestCase classes 运行 它们具有不同的参数。
在谷歌搜索问题时,我发现最好的事情是重载 load_tests()
并一个接一个地添加所有测试方法(这意味着在 运行 设置每个测试方法之前设置对象,而不是每个场景一次)。
感谢@jonrsharpe 的提示,我设法做到了。
我的解决方案是动态创建 类,然后使用 load_tests
:
def create_test_case(testcase_name, scenario_data):
class ScenarioTestCase(BaseTestCase):
@classmethod
def setUpClass(cls):
cls.fillClassVariables(scenario_data)
return_class = ScenarioTestCase
return_class.__name__ = testcase_name #for separating the results
return return_class
def load_tests(loader, tests, pattern):
list_scenario_names = [...]
list_scenario_data = [...]
loader = unittest.TestLoader()
tests = TestSuite()
for scenario_name, scenario_data in zip(list_scenario_names, list_scenario_data):
tests.addTests(loader.loadTestsFromTestCase(
create_test_case(scenario_name, scenario_data)))
return tests
通过这种方式,可以使用不同的参数动态创建测试用例,并在 PyCharm 的测试运行程序选项卡中单独列出。
虽然这有一个公认的答案,但我想记录如何使用 subclassing 来做到这一点,因为我花了很长时间才找到这种解决方案的细节。在我的例子中,目标是使用多种方法的 TestCase class 有一个 class fixture(在文件系统上设置文件以测试 cli 工具),并在参数化中稍微改变一下。
# Inherit from object to not run this abstract class
class TemporaryFolderClassSetup(object):
@classmethod
def setUpClass(cls):
try:
cls._root = tempfile.mkdtemp()
# .. create some files here ...
# allow subclasses to manipulate file tre
cls.prepare_directory(cls._root)
except Exception as e:
cls.tearDownClass()
raise
@classmethod
def tearDownClass(cls):
shutil.rmtree(cls._root)
@classmethod
def prepare_directory(cls, root):
pass
# test methods that will run in each subclass
def testX():
pass
# scenariotest, must inherit from superclass first, before unittest.TestCase)
class ScenarioTests(TemporaryFolderClassSetup, unittest.TestCase):
# ... called by parent class
@classmethod
def prepare_directory(cls, root):
pass
# test only for this scenario
def testY(self):
pass