在python中从套件向TestCase提供参数
来自python文档(http://docs.python.org/library/unittest.html): 下面是如何调用这些测试用例:在python中从套件向TestCase提供参数,python,unit-testing,testcase,Python,Unit Testing,Testcase,来自python文档(http://docs.python.org/library/unittest.html): 下面是如何调用这些测试用例: def suite(): suite = unittest.TestSuite() suite.addTest(WidgetTestCase('test_default_size')) suite.addTest(WidgetTestCase('test_resize')) return suite 是否可以在Widg
def suite():
suite = unittest.TestSuite()
suite.addTest(WidgetTestCase('test_default_size'))
suite.addTest(WidgetTestCase('test_resize'))
return suite
是否可以在WidgetTestCase中插入参数custom_参数,如:
class WidgetTestCase(unittest.TestCase):
def setUp(self,custom_parameter):
self.widget = Widget('The widget')
self.custom_parameter=custom_parameter
?我不这么认为,安装程序的签名需要是unittest所期望的,那么,安装程序在testcase的run方法中自动调用为setUp()。。。除非覆盖所需的var中的run to pass,否则无法传递它。但我认为,您想要的与单元测试的目的背道而驰。不要试图用枯燥的哲学来解释这一点,您测试的每个单元都应该是类的一部分,甚至是函数/方法的一部分 这是我最近一直在想的事情。是的,这是很有可能做到的。我叫它,但我认为参数化可能更准确。我提出了一个概念证明作为要点。简而言之,它是一个元类,允许您定义一个场景并对其运行测试。有了它,您的示例可以是这样的:
class WidgetTestCase(unittest.TestCase):
__metaclass__ = ScenarioMeta
class widget_width(ScenerioTest):
scenarios = [
dict(widget_in=Widget("One Way"), expected_tuple=(50, 50)),
dict(widget_in=Widget("Another Way"), expected_tuple=(100, 150))
]
def __test__(self, widget_in, expected_tuple):
self.assertEqual(widget_in.size, expected_tuple)
运行时,元类会写出两个单独的测试,因此输出类似:
$python myscerariotest.py-v
测试小部件宽度0(\uuuuu main\uuuuu.widget\uu width)。。。好啊
测试小部件宽度1(\uuuuu main\uuuuu.widget\uu width)。。。好啊
----------------------------------------------------------------------
在0.001s内运行了2次测试
好啊
如您所见,场景在运行时转换为测试
现在我还不确定这是否是个好主意。我在测试中使用它,在测试中,我有很多以文本为中心的案例,这些案例在稍微不同的数据上重复相同的断言,这有助于我捕获一些小的边缘案例。但这一要点中的课程确实有效,我相信它能实现你的目标
注意,通过一些技巧,测试用例可以被命名,甚至可以从外部源(如文本文件或数据库)中提取。它还没有被记录下来,但是在元类中进行一些挖掘应该可以让你开始。在我的帖子里还有更多的信息和例子
编辑
这是一个丑陋的黑客,我不再支持了。实现应该作为TestCase的一个子类完成,而不是作为一个被黑客攻击的元类。生活和学习。一个更好的解决方案是使用。我已经找到了一种方法来做到这一点,但这有点困难 基本上,我要做的是在TestCase中添加一个
\uuuuuu init\uuuuuu
方法,该方法定义一个“默认”参数和一个\uuuuuuu str\uuuuu
,以便我们能够区分以下情况:
class WidgetTestCase(unittest.TestCase):
def __init__(self, methodName='runTest'):
self.parameter = default_parameter
unittest.TestCase.__init__(self, methodName)
def __str__(self):
''' Override this so that we know which instance it is '''
return "%s(%s) (%s)" % (self._testMethodName, self.currentTest, unittest._strclass(self.__class__))
然后在suite()中,我迭代我的测试参数,用一个特定于每个测试的参数替换默认参数:
def suite():
suite = unittest.TestSuite()
for test_parameter in test_parameters:
loadedtests = unittest.TestLoader().loadTestsFromTestCase(WidgetTestCase)
for t in loadedtests:
t.parameter = test_parameter
suite.addTests(loadedtests)
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(OtherWidgetTestCases))
return suite
其中,OtherWidgetTestCases
是不需要参数化的测试
例如,我对真实数据进行了一系列测试,需要对每个数据进行一系列测试,但我也有一些合成数据集,用于测试数据中通常不存在的某些边缘情况,我只需要对这些情况进行某些测试,因此,他们在
其他WidgetTestCases
中进行自己的测试,我认为这不是一个好主意。单元测试应该足够彻底,以便在您的情况下测试所有功能,因此不需要传递不同的参数
你提到你正在传递一个www地址——这几乎肯定不是一个好主意。如果您尝试在网络连接中断的机器上运行测试,会发生什么情况?你的测试应该是:
- 自动-它们将在支持您的应用程序的所有机器和平台上运行,无需用户干预。他们不应该依靠外部环境来通过。这意味着(除其他外)依靠正确设置的互联网连接是一个坏主意。您可以通过提供虚拟数据来解决这个问题。与其将URL传递给资源,不如将数据源抽象出来并传递数据流或其他内容。这在python中尤其容易,因为您可以使用python的duck类型来表示类似流的对象(正是出于这个原因,python经常使用“类似文件”的对象!)
- 彻底-您的单元测试应该有100%的代码覆盖率,并覆盖所有可能的情况。你想用多个站点测试你的代码吗?相反,使用站点可能包含的所有功能测试代码。如果不了解您的应用程序的更多功能,我无法在这一点上提供太多建议
我意识到这不是你想要的答案,但我认为如果你遵循这些原则,从长远来看你会有更多的乐趣。我所做的就是刚刚添加的测试套件模块
WidgetTestCase.CustomParameter="some_address"
最简单的解决方案是最好的:)我想你必须使用
setattr
custom\u参数包含www地址来测试。我可以为我必须测试的每个站点编写另一个单元测试,但这将是一个代码重复,因为我们使用的是unittest
框架,并不一定意味着我们在进行单元测试。在我的例子中,为了获得完整的代码覆盖率,我需要十几个输入文件,覆盖不同的用例。我需要在每个函数上测试六个函数,因此我没有编写72个不同的测试,而是编写了一个测试用例类,其中包含6个函数中的每个函数的测试,并多次将其添加到测试套件中,每个测试文件一次,使用字典存储预期结果。它产生了更干净、更简单、更不容易出错的测试代码,不需要为不同的输入数据编写多个测试。这显然是荒谬的。在您的问题中,您从未提到您没有编写单元测试,因此我认为假设您正在使用
def suite():
suite = unittest.TestSuite()
for test_parameter in test_parameters:
loadedtests = unittest.TestLoader().loadTestsFromTestCase(WidgetTestCase)
for t in loadedtests:
t.parameter = test_parameter
suite.addTests(loadedtests)
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(OtherWidgetTestCases))
return suite
WidgetTestCase.CustomParameter="some_address"