如何正确排序单元测试测试用例? [英] How to sort unittest TestCases properly?

查看:71
本文介绍了如何正确排序单元测试测试用例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

例如,我希望它们按照它们在文件中出现的顺序运行.

For instance, I want these to run in the order they appear in the file.

import unittest

class Test_MyTests(unittest.TestCase):

    def test_run_me_first(self): pass
    def test_2nd_run_me(self):   pass
    def test_and_me_last(self):  pass

class Test_AnotherClass(unittest.TestCase):

    def test_first(self):        pass
    def test_after_first(self):  pass
    def test_de_last_ding(self): pass

if __name__ == "__main__":
    unittest.main(verbosity=2)

运行这个给

test_after_first (__main__.Test_AnotherClass) ... ok
test_de_last_ding (__main__.Test_AnotherClass) ... ok
test_first (__main__.Test_AnotherClass) ... ok
test_2nd_run_me (__main__.Test_MyTests) ... ok
test_and_me_last (__main__.Test_MyTests) ... ok
test_run_me_first (__main__.Test_MyTests) ... ok

不是我想要的.

在搜索完所有内容后,我在 SO 上找到的答案要么四处走动,要么通过调用/分组测试或说来避免该问题

The answers I've found here on SO after searching all either dance around and avoid the issue by calling / grouping tests or saying

  • 不要这样做,只是用不同的方式编写测试"或

  • "don't do it, just write your tests differently" or

按字典顺序命名您的测试!"

"name your tests lexicographically!"

...除了一个,它符合我的要求:

...except for one, which does what I want:

loader = unittest.TestLoader()
ln = lambda f: getattr(MyTestCase, f).im_func.func_code.co_firstlineno
lncmp = lambda a, b: cmp(ln(a), ln(b))
loader.sortTestMethodsUsing = lncmp
unittest.main(testLoader=loader, verbosity=2)

但仅适用于一个 TestCase 类,并且仅适用于 Python 2.

but only for one TestCase class, and only in Python 2.

我想运行我所有的 Python 3 unittest.TestCase 子类,并且我希望能够指定用于排序的确切算法.

I want to run all my Python 3 unittest.TestCase subclasses, and I'd like to be able to specify the exact algorithm to use for ordering.

我可以在 unittest 中做到这一点吗?

Can I do this in unittest?

推荐答案

经过很多的研究,得到了 SO 和 Python 的 help 的大力帮助,而不是完全通过 unittest 的文档,我得到了最初想要的答案,所以我想我会写这篇文章来帮助其他人,因为这是一个公平(而且显然很常见)的请求.

After doing a lot of research, aided greatly by SO and Python's help and not at all by unittest's documentation, I got the answer I initially wanted so I figured I'd write this up to help others, because this is a fair (and apparently common) request.

要运行特定的测试用例,我们需要为该测试用例创建一个新的 TestSuite.让我们为任意数量的测试用例这样做:

To run a specific test case, we need to make a new TestSuite for that TestCase. Let's do that for any number of TestCases:

def suiteFactory(*testcases):

    ln    = lambda f: getattr(tc, f).__code__.co_firstlineno
    lncmp = lambda a, b: ln(a) - ln(b)

    test_suite = unittest.TestSuite()
    for tc in testcases:
        test_suite.addTest(unittest.makeSuite(tc, sortUsing=lncmp))

    return test_suite

很简单:

  1. 定义一个函数来获取函数的行号.在 Python 3 中,我们之后的属性从 func.im_func.func_code.co_firstlineno 更改为 func.__code__.co_firstlineno,您可以使用 dir(anyFunction).

  1. Define a function to get a function's line number. In Python 3, the attribute we're after changed from func.im_func.func_code.co_firstlineno to func.__code__.co_firstlineno, which you can see using dir(anyFunction).

定义一个函数来根据 cmp 的行号对两个参数进行排序.cmp 不在 Python 3 中,因为 People Can Do Math,所以为了可读性,我刚刚做了它所做的.

Define a function to sort two arguments based on cmping their line numbers. cmp isn't in Python 3 on account of People Can Do Math, so I've just done exactly what it did in the interest of readability.

new 设为空白 TestSuite(),然后给它一个或十个 TestCase,然后告诉它使用第 2 点对该 TestCase 的方法进行排序:cmp输入他们的行号.

Make a new blank TestSuite(), and give it a TestCase or ten, then tell it to sort that TestCase's methods using point #2: cmping their line numbers.

<小时>

现在我们需要对文件的 TestCase 子类进行排序.


Now we need to sort the file's TestCase subclasses.

为此,我们可以查看 globals() 及其属性.

To do this, we can look at the globals() and their attributes.

def caseFactory():

    from inspect import findsource

    g = globals().copy()

    cases = [
        g[obj] for obj in g
            if obj.startswith("Test")
            and issubclass(g[obj], unittest.TestCase)
    ]

    ordered_cases = sorted(cases, key=lambda f: findsource(f)[1])

    return ordered_cases

这将获取所有以 Test 开头的 unittest.TestCase 子类,或您喜欢的任何命名约定,然后按行号对它们进行排序:findsource(object) 返回源代码,行号为索引1,这是我们关心的.

This will just get all the subclasses of unittest.TestCase that begin with Test, or any naming convention you prefer, and then sort them by their line number: findsource(object) returns source code, and line number as index 1, which is what we care about.

把它包装成我们可以使用的东西:

To wrap it into something we can use:

if __name__ == "__main__":
    cases = suiteFactory(*caseFactory())
    runner = unittest.TextTestRunner(verbosity=2)
    runner.run(cases)

确实分隔了输出,但如果最低级别的测试位于文件的顶部(或底部,或某处),并且应该运行在更高级别的测试之前.

This does compartmentalise the output, but probably a good thing if the lowest-level tests are at the top (or bottom, or somewhere) in the file, and should run before the higher-level tests.

所以完整的输出是:

test_run_me_first (__main__.Test_MyTests) ... ok
test_2nd_run_me (__main__.Test_MyTests) ... ok
test_and_me_last (__main__.Test_MyTests) ... ok
test_first (__main__.Test_AnotherClass) ... ok
test_after_first (__main__.Test_AnotherClass) ... ok
test_de_last_ding (__main__.Test_AnotherClass) ... ok

----------------------------------------------------------------------
Ran 6 tests in 0.000s

OK

成功!

您可以在 Github gist 上找到更有趣的版本.

这篇关于如何正确排序单元测试测试用例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆