来自python文档(http://docs.python.org/library/unittest.html):
import unittest
class WidgetTestCase(unittest.TestCase):
def setUp(self):
self.widget = Widget('The widget')
def tearDown(self):
self.widget.dispose()
self.widget = None
def test_default_size(self):
self.assertEqual(self.widget.size(), (50,50),
'incorrect default size')
def test_resize(self):
self.widget.resize(100,150)
self.assertEqual(self.widget.size(), (100,150),
'wrong size after resize')
以下是如何调用这些测试用例:
def suite():
suite = unittest.TestSuite()
suite.addTest(WidgetTestCase('test_default_size'))
suite.addTest(WidgetTestCase('test_resize'))
return suite
是否可以将参数custom_parameter插入WidgetTestCase,如:
class WidgetTestCase(unittest.TestCase):
def setUp(self,custom_parameter):
self.widget = Widget('The widget')
self.custom_parameter=custom_parameter
答案 0 :(得分:6)
我所做的是刚刚添加的test_suite模块
WidgetTestCase.CustomParameter="some_address"
最简单的解决方案是最好的:)
答案 1 :(得分:3)
这是我最近想到的事情。是的,这是非常可能的。我称之为scenario testing,但我认为参数化可能更准确。我把概念证明作为要点here。简而言之,它是一个元类,允许您定义一个场景并对其进行一系列测试。有了它你的例子可以是这样的:
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)
运行时,元类会写出2个单独的测试,因此输出类似于:
$ python myscerariotest.py -v test_widget_width_0 (__main__.widget_width) ... ok test_widget_width_1 (__main__.widget_width) ... ok ---------------------------------------------------------------------- Ran 2 tests in 0.001s OK
正如您所看到的,场景在运行时转换为测试。
现在我还不确定这是不是一个好主意。我在测试中使用它,我有很多以文本为中心的情况,在稍微不同的数据上重复相同的断言,这有助于我抓住小边缘情况。但是那个要点中的课程确实有效,我相信它能完成你所追求的目标。
请注意,通过一些技巧,测试用例可以被赋予名称,甚至可以从外部源(如文本文件或数据库)中提取。它没有记录,但在元类中的一些挖掘应该让你开始。我的帖子here还有更多信息和示例。
这是一个丑陋的黑客,我不再支持了。该实现应该作为TestCase的子类完成,而不是作为被黑客攻击的元类。活到老,学到老。更好的解决方案是使用nose generators。
答案 2 :(得分:3)
我找到了一种方法来做到这一点,但它有点像淤泥。
基本上,我所做的是在TestCase中添加__init__
方法,该方法定义'default'参数和__str__
,以便我们区分案例:
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
是不需要参数化的测试。
例如,我对实际数据进行了大量测试,需要对每个测试应用一套测试,但我也有一些合成数据集,用于测试通常不存在于数据中的某些边缘情况,以及我只需要对这些测试应用某些测试,因此他们可以在OtherWidgetTestCases
中进行自己的测试。
答案 3 :(得分:0)
我不相信,setUp的签名需要是unittest所期望的,afaik,setUp在testcase的run方法中自动调用为setUp()...你将无法通过除非你重写run以传递你想要的var。但我认为你想要的东西会击败单位测试的目的。不要试图使用DRY哲学,你正在测试的每个单元应该是一个类的一部分,甚至是函数/方法的一部分。
答案 4 :(得分:0)
我不认为这是个好主意。单元测试应该足够彻底,以便您测试案例中的所有功能,因此不需要传递不同的参数。
你提到你正在传递一个www地址 - 这几乎肯定不是一个好主意。如果您尝试在网络连接断开的计算机上运行测试会发生什么?你的测试应该是:
自动 - 它们将在支持您的应用的所有计算机和平台上运行,无需用户干预。他们不应该依赖外部环境来传递。这意味着(除其他事项外)依赖正确建立的互联网连接是一个坏主意。您可以通过提供虚拟数据来解决这个问题。而不是将URL传递给资源,抽象出数据源并传入数据流或其他任何东西。这在python中特别容易,因为你可以使用python的duck-typing来呈现类似流的对象(python经常使用“类似文件”的对象出于这个原因!)。
彻底 - 您的单元测试应具有100%的代码覆盖率,并涵盖所有可能的情况。您想要使用多个站点测试您的代码吗?而是使用站点可能包含的所有可能功能测试您的代码。如果不了解您的应用程序的功能,我就不能提供太多建议。
现在,看起来你的测试将是大量数据驱动的。有许多工具允许您为单元测试定义数据集并在测试中加载它们。例如,查看python测试夹具。
我意识到这不是你正在寻找的答案,但我认为如果你遵循这些原则,从长远来看你会有更多的快乐。