【问题标题】:How to run unittest test cases in the order they are declared如何按照声明的顺序运行单元测试测试用例
【发布时间】:2018-09-24 02:46:40
【问题描述】:

我完全意识到单元测试的顺序并不重要。但是这些单元测试与实际单元测试一样用于教学用途,所以我希望测试输出与测试用例源代码相匹配。

我看到有一种方法可以通过在测试加载器上设置sortTestMethodsUsing 属性来设置排序顺序。默认是一个简单的cmp() 调用,以词法比较名称。所以我尝试编写一个类似于cmp 的函数,该函数将采用两个名称,找到它们的声明行号并返回它们的cmp()-等价物:

import unittest

class TestCaseB(unittest.TestCase):
    def test(self):
        print("running test case B")

class TestCaseA(unittest.TestCase):
    def test(self):
        print("running test case A")

import inspect
def get_decl_line_no(cls_name):
    cls = globals()[cls_name]
    return inspect.getsourcelines(cls)[1]

def sgn(x):
    return -1 if x < 0 else 1 if x > 0 else 0

def cmp_class_names_by_decl_order(cls_a, cls_b):
    a = get_decl_line_no(cls_a)
    b = get_decl_line_no(cls_b)
    return sgn(a - b)

unittest.defaultTestLoader.sortTestMethodsUsing = cmp_class_names_by_decl_order
unittest.main()

当我运行它时,我得到这个输出:

running test case A
.running test case B
.
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

表示测试用例没有按照声明顺序运行。

我的排序函数没有被调用,所以我怀疑 main() 正在构建一个新的测试加载器,它正在清除我的排序函数。

【问题讨论】:

  • 你能提供一个minimal reproducible example 来证明你的问题吗?您发布的代码不包含任何测试,因此不需要对任何测试进行排序。
  • (如果这你运行的代码,那么这就是你的答案:它没有排序任何东西,因为没有什么要排序。)
  • 顺便说一句,我猜这是一个 Python2 项目,对吧?因为 Python3 中没有 cmp
  • 实际上它是一个库模块,试图保持与 Py2.6 到 3.latest 的兼容性。我忘记了 Py3 不再有 cmp() - 感谢您的关注。
  • here 是一个相关的答案,如果您真的想对类而不是方法进行排序,我认为它可能会对您有所帮助。

标签: python python-3.x python-unittest


【解决方案1】:

解决方案是显式创建一个 TestSuite,而不是让 unittest.main() 遵循其所有默认测试发现和排序行为。这是我如何让它工作的:

import unittest

class TestCaseB(unittest.TestCase):
    def runTest(self):
        print("running test case B")

class TestCaseA(unittest.TestCase):
    def runTest(self):
        print("running test case A")


import inspect
def get_decl_line_no(cls):
    return inspect.getsourcelines(cls)[1]

# get all test cases defined in this module
test_case_classes = list(filter(lambda c: c.__name__ in globals(), 
                                unittest.TestCase.__subclasses__()))

# sort them by decl line no
test_case_classes.sort(key=get_decl_line_no)

# make into a suite and run it
suite = unittest.TestSuite(cls() for cls in test_case_classes)
unittest.TextTestRunner().run(suite)

这给出了所需的输出:

running test case B
.running test case A
.
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

需要注意的是,每个类中的测试方法必须命名为runTest

【讨论】:

    【解决方案2】:

    您可以手动构建一个 TestSuite,您的 TestCases 和其中的所有测试都按行号运行:

    # Python 3.8.3
    import unittest
    import sys
    import inspect
    
    
    def isTestClass(x):
        return inspect.isclass(x) and issubclass(x, unittest.TestCase)
    
    
    def isTestFunction(x):
        return inspect.isfunction(x) and x.__name__.startswith("test")
    
    
    class TestB(unittest.TestCase):
        def test_B(self):
            print("Running test_B")
            self.assertEqual((2+2), 4)
    
        def test_A(self):
            print("Running test_A")
            self.assertEqual((2+2), 4)
    
        def setUpClass():
            print("TestB Class Setup")
    
    
    class TestA(unittest.TestCase):
        def test_A(self):
            print("Running test_A")
            self.assertEqual((2+2), 4)
    
        def test_B(self):
            print("Running test_B")
            self.assertEqual((2+2), 4)
    
        def setUpClass():
            print("TestA Class Setup")
    
    
    def suite():
    
        # get current module object
        module = sys.modules[__name__]
    
        # get all test className,class tuples in current module
        testClasses = [
            tup for tup in
            inspect.getmembers(module, isTestClass)
        ]
    
        # sort classes by line number
        testClasses.sort(key=lambda t: inspect.getsourcelines(t[1])[1])
    
        testSuite = unittest.TestSuite()
    
        for testClass in testClasses:
            # get list of testFunctionName,testFunction tuples in current class
            classTests = [
                tup for tup in
                inspect.getmembers(testClass[1], isTestFunction)
            ]
    
            # sort TestFunctions by line number
            classTests.sort(key=lambda t: inspect.getsourcelines(t[1])[1])
    
            # create TestCase instances and add to testSuite;
            for test in classTests:
                testSuite.addTest(testClass[1](test[0]))
    
        return testSuite
    
    
    if __name__ == '__main__':
    
        runner = unittest.TextTestRunner()
        runner.run(suite())
    
    

    输出:

    TestB Class Setup
    Running test_B
    .Running test_A
    .TestA Class Setup
    Running test_A
    .Running test_B
    .
    ----------------------------------------------------------------------
    Ran 4 tests in 0.000s
    
    OK
    

    【讨论】:

      【解决方案3】:

      顾名思义,sortTestMethodsUsing 用于对测试方法进行排序。它不用于对类进行排序。 (它也不用于对不同类中的方法进行排序;不同的类分别处理。)

      如果您在同一个类中有两个测试方法,sortTestMethodsUsing 将用于确定它们的顺序。 (此时,您会收到异常,因为您的函数需要类名。)

      【讨论】:

      • 虽然这让我了解了为什么我在示例代码中尝试的方法不能达到我想要的效果,但我不确定它是否有资格作为实际问题的“答案”..
      猜你喜欢
      • 1970-01-01
      • 2012-03-28
      • 2011-05-04
      • 2012-01-08
      • 2015-12-21
      • 2015-09-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多