我正在学习Python并且一直在尝试更多地了解Python的unittest
模块的细节。该文档包括以下内容:
为了便于运行测试,正如我们所做的那样 稍后会看到,这是一个好主意 在每个测试模块中提供可调用的 返回预构建测试的对象 套房:
def suite(): suite = unittest.TestSuite() suite.addTest(WidgetTestCase('testDefaultSize')) suite.addTest(WidgetTestCase('testResize')) return suite
据我所知,没有解释这样做的目的。另外,我无法弄清楚如何使用这种方法。我尝试了几件事没有成功(除了了解我得到的错误消息):
import unittest
def average(values):
return sum(values) / len(values)
class MyTestCase(unittest.TestCase):
def testFoo(self):
self.assertEqual(average([10,100]),55)
def testBar(self):
self.assertEqual(average([11]),11)
def testBaz(self):
self.assertEqual(average([20,20]),20)
def suite():
suite = unittest.TestSuite()
suite.addTest(MyTestCase('testFoo'))
suite.addTest(MyTestCase('testBar'))
suite.addTest(MyTestCase('testBaz'))
return suite
if __name__ == '__main__':
# s = MyTestCase.suite()
# TypeError: unbound method suite() must be called
# with MyTestCase instance as first argument
# s = MyTestCase.suite(MyTestCase())
# ValueError: no such test method in <class '__main__.MyTestCase'>: runTest
# s = MyTestCase.suite(MyTestCase('testFoo'))
# TypeError: suite() takes no arguments (1 given)
以下“工作”但似乎很尴尬,并且我要求将suite()
的方法签名更改为“def suite(self):
”。
s = MyTestCase('testFoo').suite()
unittest.TextTestRunner().run(s)
答案 0 :(得分:6)
您收到的第一条错误消息很有意义,并解释了很多。
print MyTestCase.suite # <unbound method MyTestCase.suite>
未结合的。这意味着除非将其绑定到实例,否则无法调用它。 MyTestCase.run
实际上是相同的:
print MyTestCase.run # <unbound method MyTestCase.run>
也许现在你不明白为什么你不能打电话给suite
,但请暂时搁置一边。您是否会尝试在课堂上拨打run
,如上所述?类似的东西:
MyTestCase.run() # ?
可能不对,对吧?写这个没有意义,它不起作用,因为run
是一个实例方法,需要一个self
实例来处理。好吧,看起来Python“理解”suite
的方式与它理解run
的方式相同,作为一种未绑定的方法。
让我们看看为什么:
如果您尝试将suite
方法放在类范围之外,并将其定义为全局函数,它就可以正常工作:
import unittest
def average(values):
return sum(values) / len(values)
class MyTestCase(unittest.TestCase):
def testFoo(self):
self.assertEqual(average([10,100]),55)
def testBar(self):
self.assertEqual(average([11]),11)
def testBaz(self):
self.assertEqual(average([20,20]),20)
def suite():
suite = unittest.TestSuite()
suite.addTest(MyTestCase('testFoo'))
suite.addTest(MyTestCase('testBar'))
suite.addTest(MyTestCase('testBaz'))
return suite
print suite() # <unittest.TestSuite tests=[<__main__.MyTestCase testMethod=testFoo>, <__main__.MyTestCase testMethod=testBar>, <__main__.MyTestCase testMethod=testBaz>]>
但是你不希望它超出课程范围,因为你想要调用MyTestCase.suite()
您可能认为,由于suite
有点“静态”或与实例无关,因此放置self
参数没有意义,是吗?
没错。
但是如果你在Python类中定义一个方法,Python会期望该方法有一个self
参数作为第一个参数。省略self
参数不会自动生成方法static
。如果要定义“静态”方法,则必须使用staticmethod装饰器:
@staticmethod
def suite():
suite = unittest.TestSuite()
suite.addTest(MyTestCase('testFoo'))
suite.addTest(MyTestCase('testBar'))
suite.addTest(MyTestCase('testBaz'))
return suite
这样Python不会将MyTestCase视为实例方法,而是将其视为函数:
print MyTestCase.suite # <function suite at 0x...>
当然,现在您可以致电MyTestCase.suite()
,这将按预期工作。
if __name__ == '__main__':
s = MyTestCase.suite()
unittest.TextTestRunner().run(s) # Ran 3 tests in 0.000s, OK
答案 1 :(得分:1)
documentation说suite()
应该是模块中的一个函数,而不是类中的方法。它似乎只是一个便利功能,因此您可以稍后聚合许多模块的测试套件:
alltests = unittest.TestSuite([
my_module_1.suite(),
my_module_2.suite(),
])
调用函数的问题都与它在类中的方法有关,但不是作为方法编写的。 self
参数是“当前对象”,并且是实例方法所必需的。 (例如a.b(1, 2)
在概念上与b(a, 1, 2)
相同。)如果方法对类而不是实例进行操作,请阅读classmethod
。如果它只是为了方便而与类分组,但不对类或实例进行操作,那么请阅读staticmethod
。这些都不会特别帮助您使用unittest
,但它们可能有助于解释您为何看到自己所做的事情。
答案 2 :(得分:1)
有一件事需要注意,nose是一种真正简化运行测试的工具。它允许您准确指定从命令行运行哪些测试,以及遍历每个目录并运行每个测试。
答案 3 :(得分:1)
正如已经提到的,文档将suite()称为模块中的方法,而unittest(奇怪地)似乎没有对此方法进行任何特殊识别,因此您必须明确地调用它。但是,如果您使用名为“testoob”的工具,它会自动调用suite()方法(如果您为其main()指定defaultTest =“suite”参数)并在其上添加其他几个功能。基本单元测试包。它还提供了生成XML文件的选项,这些文件包括从这些测试中收集的stdout和stderr(这对于自动化测试来说是一大优点),并且还可以生成HTML报告(尽管您需要安装其他软件包)。我无法找到一种方法来自动发现鼻子声称支持的所有测试,所以鼻子可能是更好的选择。
答案 4 :(得分:0)
我建议使用以下内容。这使您无需手动输入随时添加的所有测试。
def suite():
suite = unittest.TestLoader().loadTestsFromTestCase(Your_Test_Case_Class)
return suite
通过定义:
,您可以灵活地在同一模块中执行测试if __name__ == "__main__":
suite()
如果你想将套件捆绑在另一个模块中,例如test_suite.py(例如),那么可以通过以下方式完成:
导入test_module名称 import unittest
if __name__=="__main__":
suite1=test_module_name.suite()
...
...
alltests = unittest.TestSuite([suite1,suite2])
现在如何运行测试。我通常使用更简单的方法在包级别执行此命令来运行,并且unittest自动发现测试:
python -m unittest discover
或
nosetests
警告:单元测试比鼻子测试快X倍,因此它最多取决于开发人员的偏好,特别是如果他们使用了第三方鼻子插件并希望继续使用它。