代码之家  ›  专栏  ›  技术社区  ›  FMc TLP

对于python unittest,如何创建和使用“返回测试套件的可调用对象”?

  •  5
  • FMc TLP  · 技术社区  · 17 年前

    我正在学习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)
    
    5 回复  |  直到 15 年前
        1
  •  6
  •   Nicolas Dumazet    17 年前

    您得到的第一条错误消息是有意义的,并且解释了很多。

    print MyTestCase.suite # <unbound method MyTestCase.suite>
    

    未绑定的 . 这意味着除非将其绑定到实例,否则无法调用它。事实上,对于 MyTestCase.run :

    print MyTestCase.run # <unbound method MyTestCase.run>
    

    也许现在你不明白为什么打不到电话 suite ,但请暂时放在一边。你能打个电话吗 run 在课堂上,像上面一样?类似:

    MyTestCase.run() # ?
    

    可能不是,对吧?写这个没有意义,也不会起作用,因为 运行 是实例方法,需要 self 要处理的实例。看来巨蟒“理解” 一套 以同样的方式理解 运行 ,作为未绑定的方法。

    让我们来看看为什么:

    如果你试图把 一套 方法超出类范围,并将其定义为全局函数,它只起作用:

    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()

    你可能认为从那以后 一套 有点“静态”,或者说独立于实例,把 自己 争论,是吗? 这是对的。

    但是,如果在Python类中定义一个方法,那么Python将期望该方法具有 自己 作为第一个参数的参数。只是省略了 自己 参数不能使您的方法 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
    
        2
  •  1
  •   Roger Pate    17 年前

    这个 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 但他们可能有助于解释为什么你看到了你所做的。

        3
  •  1
  •   Jason Baker    17 年前

    需要注意的一点是, nose 是一个真正简化运行测试的工具。它允许您精确地指定从命令行运行的测试,以及遍历每个目录并运行每个测试。

        4
  •  1
  •   haridsv    16 年前

    正如前面提到的,文档将suite()作为模块中的一个方法来引用,而unittest(奇怪的是)似乎对这个方法没有任何特殊的识别,因此您必须显式地调用它。但是,如果使用一个名为“的工具, testoob “,它会自动调用suite()方法(如果您在其main()中指定了defaulttest=”suite“参数),并在基本UnitTest包的顶部添加了其他几个功能。它还提供了用于生成XML文件的选项,其中包括从这些测试中收集到的stdout和stderr(对于自动化测试来说,这是一大优势),还可以生成HTML报告(尽管您需要安装其他包)。我找不到一种方法来自动发现鼻子声称支持的所有测试,所以鼻子可能是更好的选择。

        5
  •  0
  •   okm    15 年前

    我建议使用以下内容。这样可以避免在进行过程中手动输入所有添加的测试。

    def suite():
        suite = unittest.TestLoader().loadTestsFromTestCase(Your_Test_Case_Class)
        return suite
    

    通过定义以下内容,您可以灵活地在同一模块中执行测试:

    if __name__ == "__main__":
         suite()
    

    如果您想将您的套件捆绑在另一个模块中,即test_suite.py(例如),那么可以通过以下方式完成:

    导入测试\模块名称 进口统一测试

    if __name__=="__main__":
        suite1=test_module_name.suite()
        ...
        ...
        alltests = unittest.TestSuite([suite1,suite2])
    

    现在如何运行测试。我通常使用更简单的方法在包级别执行此命令来运行,UnitTest自动发现测试:

    python -m unittest discover
    

    nosetests 
    

    Caveat: UnitTest比NoseTest快X倍,因此它取决于开发人员的偏好,特别是如果他们使用了第三方的NoseTest插件并希望继续使用它。