Python unittest.TestCase执行顺序

Mik*_*ike 68 python unit-testing

Python中有没有办法unittest设置运行测试用例的顺序?

在我目前的TestCase课程中,一些测试用例具有副作用,为其他测试用例设置正常运行的条件.现在我意识到这样做的正确方法是使用setUp()所有设置实现的东西,但我想实现一个设计,其中每个连续的测试建立稍微更多的状态,下一个可以使用.我发现这更优雅.

class MyTest(TestCase):
  def test_setup(self):
   #do something
  def test_thing(self)
   #do something that depends on test_setup()
Run Code Online (Sandbox Code Playgroud)

理想情况下,我希望测试按照它们在课堂中出现的顺序运行.它们似乎按字母顺序运行.

nco*_*lan 66

不要让它们独立测试 - 如果你想进行单片测试,那就写一个单片测试.

class Monolithic(TestCase):
  def step1(self):
      ...

  def step2(self):
      ...

  def _steps(self):
    for name in dir(self): # dir() result is implicitly sorted
      if name.startswith("step"):
        yield name, getattr(self, name) 

  def test_steps(self):
    for name, step in self._steps():
      try:
        step()
      except Exception as e:
        self.fail("{} failed ({}: {})".format(step, type(e), e))
Run Code Online (Sandbox Code Playgroud)

如果测试稍后开始失败并且您想要了解所有失败步骤的信息而不是在第一个失败步骤中停止测试用例,则可以使用以下subtests功能:https://docs.python.org/3/library/unittest.html#区分测试迭代-使用-子测试

(通过unittest2Python 3.4之前的版本可以使用子测试功能:https://pypi.python.org/pypi/unittest2)

  • 纯单元测试提供的好处是,当它们失败时,它们通常会告诉您*确切的*出了什么问题.您还可以重新运行尝试修复它们时失败的测试.像这样的单片测试没有这些好处:当它们失败时,这是一个调试练习,以找出问题所在.另一方面,这样的测试通常更容易和更快地编写,特别是在将测试改进到未考虑单元测试的现有应用程序时. (8认同)
  • @shakirthow如果执行顺序很重要,它们不再是单元测试 - 它们是场景测试中的步骤.这仍然是值得做的事情,但它最好处理如图所示的更大的测试用例,或使用更高级别的行为测试框架,如http://pythonhosted.org/behave/ (4认同)

var*_*run 34

总是为这样的期望写一个单一的测试是一个很好的做法,但是如果你像我一样傻傻的家伙,那么你可以简单地按字母顺序编写难看的方法,以便它们从a到b排序,如python docs http中所述://docs.python.org/library/unittest.html

请注意,运行各种测试用例的顺序是通过根据字符串的内置顺序对测试函数名称进行排序来确定的.

例:

  def test_a_first():
  print "1"
  def test_b_next(): 
  print "2" 
  def test_c_last(): 
  print "3"
Run Code Online (Sandbox Code Playgroud)

  • IMO这种方法比添加更多代码作为解决方法更好。 (2认同)

ken*_*ytm 24

http://docs.python.org/library/unittest.html

请注意,运行各种测试用例的顺序是通过根据字符串的内置顺序对测试函数名称进行排序来确定的.

所以只要确保test_setup名称的字符串值最小.

请注意,您不应该依赖此行为 - 不同的测试函数应该独立于执行顺序.如果您明确需要订单,请参阅ngcohlan上面的答案以获得解决方案.

  • 不同的testrunner,不同的行为.您的建议对于编写稳定的代码和测试没有帮助. (6认同)

hoc*_*age 16

老问题,但我没有看到在任何相关问题中列出的另一种方式:使用aTestSuite.

完成排序的另一种方法是将测试添加到a unitest.TestSuite.这似乎尊重测试添加到套件中的顺序suite.addTest(...).去做这个:

  • 创建一个或多个TestCase子类,

    class FooTestCase(unittest.TestCase):
        def test_ten():
            print('Testing ten (10)...')
        def test_eleven():
            print('Testing eleven (11)...')
    
    class BarTestCase(unittest.TestCase):
        def test_twelve():
            print('Testing twelve (12)...')
        def test_nine():
            print('Testing nine (09)...')
    
    Run Code Online (Sandbox Code Playgroud)
  • 创建一个按所需顺序添加的可调用测试套件生成,根据文档此问题进行调整:

    def suite():
        suite = unittest.TestSuite()
        suite.addTest(BarTestCase('test_nine'))
        suite.addTest(FooTestCase('test_ten'))
        suite.addTest(FooTestCase('test_eleven'))
        suite.addTest(BarTestCase('test_twelve'))
        return suite
    
    Run Code Online (Sandbox Code Playgroud)
  • 执行测试套件,例如,

    if __name__ == '__main__':
        runner = unittest.TextTestRunner(failfast=True)
        runner.run(suite())
    
    Run Code Online (Sandbox Code Playgroud)

对于上下文,我需要这个,并且对其他选项不满意.我决定采用上面的测试排序方式.我没有看到这个TestSuite方法列出了几个"单元测试排序问题"中的任何一个(例如,这个问题和其他包括执行顺序,或更改顺序测试顺序).


cai*_*aio 5

我最终得到了一个对我有用的简单解决方案:

class SequentialTestLoader(unittest.TestLoader):
    def getTestCaseNames(self, testCaseClass):
        test_names = super().getTestCaseNames(testCaseClass)
        testcase_methods = list(testCaseClass.__dict__.keys())
        test_names.sort(key=testcase_methods.index)
        return test_names
Run Code Online (Sandbox Code Playgroud)

进而

unittest.main(testLoader=utils.SequentialTestLoader())
Run Code Online (Sandbox Code Playgroud)


ggo*_*len 5

一种简单而灵活的方法是将比较器函数分配给unittest.TestLoader.sortTestMethodsUsing

用于在对方法名称getTestCaseNames()和所有loadTestsFrom*()方法进行排序时比较方法名称的函数。

最小用量:

import unittest

class Test(unittest.TestCase):
    def test_foo(self):
        """ test foo """
        self.assertEqual(1, 1)

    def test_bar(self):
        """ test bar """
        self.assertEqual(1, 1)

if __name__ == "__main__":
    test_order = ["test_foo", "test_bar"] # could be sys.argv
    loader = unittest.TestLoader()
    loader.sortTestMethodsUsing = lambda x, y: test_order.index(x) - test_order.index(y)
    unittest.main(testLoader=loader, verbosity=2)
Run Code Online (Sandbox Code Playgroud)

输出:

import unittest

class Test(unittest.TestCase):
    def test_foo(self):
        """ test foo """
        self.assertEqual(1, 1)

    def test_bar(self):
        """ test bar """
        self.assertEqual(1, 1)

if __name__ == "__main__":
    test_order = ["test_foo", "test_bar"] # could be sys.argv
    loader = unittest.TestLoader()
    loader.sortTestMethodsUsing = lambda x, y: test_order.index(x) - test_order.index(y)
    unittest.main(testLoader=loader, verbosity=2)
Run Code Online (Sandbox Code Playgroud)

这是按源代码顺序而不是默认词汇顺序运行测试的概念证明(输出如上)。

import inspect
import unittest

class Test(unittest.TestCase):
    def test_foo(self):
        """ test foo """
        self.assertEqual(1, 1)

    def test_bar(self):
        """ test bar """
        self.assertEqual(1, 1)

if __name__ == "__main__":
    test_src = inspect.getsource(Test)
    unittest.TestLoader.sortTestMethodsUsing = lambda _, x, y: (
        test_src.index(f"def {x}") - test_src.index(f"def {y}")
    )
    unittest.main(verbosity=2)
Run Code Online (Sandbox Code Playgroud)

我在这篇文章中使用了 Python 3.8.0。