如何正确排序单元测试测试用例? [英] How to sort unittest TestCases properly?
问题描述
例如,我希望它们按照它们在文件中出现的顺序运行.
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
很简单:
定义一个函数来获取函数的行号.在 Python 3 中,我们之后的属性从
func.im_func.func_code.co_firstlineno
更改为func.__code__.co_firstlineno
,您可以使用dir(anyFunction)
.
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
tofunc.__code__.co_firstlineno
, which you can see usingdir(anyFunction)
.
定义一个函数来根据 cmp
的行号对两个参数进行排序.cmp
不在 Python 3 中,因为 People Can Do Math,所以为了可读性,我刚刚做了它所做的.
Define a function to sort two arguments based on cmp
ing 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: cmp
ing 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
成功!
这篇关于如何正确排序单元测试测试用例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!