首页 > 解决方案 > python unitets的执行顺序由他们的声明

问题描述

我正在使用 python unittests 和 selenium,在我的代码中,我有一个包含许多测试用例的测试类:

class BasicRegression(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        cls.driver = webdriver.Chrome(executable_path=Data.driver)
        cls.driver.implicitly_wait(1)
        cls.driver.maximize_window()

    def testcase1_some_stuff(self):
        do_something()

    def testcase2_some_stuff(self):
        do_something()

    def testcase3_some_stuff(self):
        do_something()

    ...

    @classmethod
    def tearDownClass(cls):
        cls.driver.close()
        cls.driver.quit()

if __name__ == '__main__':
    unittest.main()

测试按字母顺序执行,即 testcase1、testcase2 和 testcase3,直到 testcase9。标准。testcase10等出现问题,先执行。

我的问题是如何设置他们的执行顺序?

标签: pythonseleniumpython-unittest

解决方案


首先,单元测试应该是独立的。所以必须是。通过执行的测试python-unittest应该以能够独立运行的方式设计。纯单元测试提供了一个好处,即当它们失败时,它们通常会描述究竟出了什么问题。我们仍然倾向于使用unittest框架编写功能测试、集成测试和系统测试,并且这些测试如果不订购它们就无法运行,因为Selenium会自动执行Browsing Context。为了实现排序,您至少需要为测试名称使用更好的命名约定,例如:test_1, test_2,test_3等,这是因为测试是根据字符串的内置排序进行排序的。

但是,根据您的观察,问题出现test_10在排序顺序似乎中断的地方等等。例如,在名称为和的 3 个测试中test_1,似乎 unittest 在之前执行:test_2test_10test_10test_2

  • 代码:

    import unittest
    
    class Test(unittest.TestCase):
    
        @classmethod
        def setUp(self):
            print("I'm in setUp")
    
        def test_1(self):
            print("I'm in test 1")
    
        def test_2(self):
            print("I'm in test 2")
    
        def test_10(self):
            print("I'm in test 10")
    
        @classmethod
        def tearDown(self):
            print("I'm in tearDown")
    
    if __name__ == "__main__":
        unittest.main()
    
  • 控制台输出:

    Finding files... done.
    Importing test modules ... done.
    
    I'm in setUp
    I'm in test 1
    I'm in tearDown
    I'm in setUp
    I'm in test 10
    I'm in tearDown
    I'm in setUp
    I'm in test 2
    I'm in tearDown
    ----------------------------------------------------------------------
    Ran 3 tests in 0.001s
    
    OK
    

解决方案

在不同的讨论中提出了不同的解决方案,其中一些解决方案如下:

  • @max 在讨论单元测试测试顺序中建议将其设置sortTestMethodsUsingNone如下:

    import unittest
    unittest.TestLoader.sortTestMethodsUsing = None
    
  • @atomocopter 在讨论更改 Python 中单元测试的顺序时建议将 设置sortTestMethodsUsing为某个值,如下所示:

    import unittest
    unittest.TestLoader.sortTestMethodsUsing = lambda _, x, y: cmp(y, x)
    
  • @ElmarZander 在讨论Unittest 测试顺序中建议使用nose和编写测试用例作为函数(而不是作为某些 TestCase 派生类的方法)nose不会改变顺序,而是使用文件中定义的函数顺序。

  • @Keiji 在讨论Controlling the order of unittest.TestCases中提到:

sortTestMethodsUsing 需要一个类似 Python 2 的函数cmp,它在 Python 3 中没有等价物(我去检查 Python 3 是否有一个<=> 宇宙飞船运算符,但显然没有;他们希望你依赖单独的比较<and ==,这似乎是一个倒退...)。该函数需要两个参数进行比较,如果第一个较小,则必须返回一个负数。值得注意的是,在这种特殊情况下,该函数可能会假设参数永远不会相等,因为 unittest不会在其测试名称列表中放置重复项。

考虑到这一点,这是我发现的最简单的方法,假设您只使用一个 TestCase 类:

def make_orderer():
    order = {}

    def ordered(f):
        order[f.__name__] = len(order)
        return f

    def compare(a, b):
        return [1, -1][order[a] < order[b]]

    return ordered, compare

ordered, compare = make_orderer()
unittest.defaultTestLoader.sortTestMethodsUsing = compare

然后,用 注释每个测试方法@ordered

class TestMyClass(unittest.TestCase):
    @ordered
    def test_run_me_first(self):
        pass

    @ordered
    def test_do_this_second(self):
        pass

    @ordered
    def test_the_final_bits(self):
        pass

if __name__ == '__main__':
    unittest.main()

这依赖于 Python 按照带注释的函数在文件中出现的顺序调用注释。据我所知,这是有意的,如果它改变了,我会感到惊讶,但我实际上不知道它是否是有保证的行为。我认为这个解决方案甚至可以在 Python 2 中工作,对于那些不幸坚持使用它的人来说,虽然我还没有机会对此进行测试。

如果您有多个 TestCase 类,则需要ordered, compare = make_orderer()在定义之前为每个类运行一次class ,尽管如何使用它sortTestMethodsUsing 会更加棘手,而且我还没有能够测试它。

作为记录,我正在测试的代码依赖于固定的测试顺序 - 我完全理解你不应该依赖测试顺序,这就是人们用来避免回答这个问题的原因。我的测试顺序可以是随机的,它也可以正常工作。但是,我希望将顺序固定为文件中定义的顺序有一个很好的理由:它使一眼就能看出哪些测试失败了。


推荐阅读