Python unittest: how to run only part of a test file?
我有一个包含花费大量时间的测试的测试文件(它们将计算发送到集群并等待结果)。所有这些都在特定的测试用例类中。
因为它们需要时间,而且不可能中断,所以我希望能够选择这部分测试是运行还是不运行(最好的方法是使用命令行参数,例如"
目前,我只使用
谢谢。
要只运行一个特定的测试,您可以使用:
1 | $ python -m unittest test_module.TestClass.test_method |
号
此处提供更多信息
默认的
您不必使用此默认行为。
例如,您可以创建三个UnitTest.TestSuite实例。
"快速"子集。
1 2 3 | fast = TestSuite() fast.addTests( TestFastThis ) fast.addTests( TestFastThat ) |
"慢"子集。
1 2 3 | slow = TestSuite() slow.addTests( TestSlowAnother ) slow.addTests( TestSlowSomeMore ) |
。
全套的。
1 | alltests = unittest.TestSuite([fast, slow]) |
请注意,我已经调整了测试用例名称,以指示快速与缓慢。您可以子类unittest.testloader解析类名称并创建多个加载程序。
然后,主程序可以使用optparse或argparse(从2.7或3.2开始提供)分析命令行参数,以选择要运行的套件,快速、慢速或全部。
或者,您可以相信
1 2 3 | if __name__ =="__main__": suite = eval(sys.argv[1]) # Be careful with this line! unittest.TextTestRunner().run(suite) |
。
我用一个简单的
1 2 3 4 5 6 7 8 | import os SLOW_TESTS = int(os.getenv('SLOW_TESTS', '0')) @unittest.skipIf(not SLOW_TESTS,"slow") class CheckMyFeature(unittest.TestCase): def runTest(self): … |
号
这样,我只需要用这一行代码来修饰一个已经存在的测试用例(不需要创建测试套件或类似的代码,只需要在我的单元测试文件的开头有一个
如果我想在缓慢的情况下执行它,我只需要这样调用我的脚本:
1 | SLOW_TESTS=1 python -m unittest … |
实际上,可以将测试用例的名称作为sys.argv传递,并且只测试那些用例。
例如,假设您
1 2 3 4 5 6 7 8 9 10 11 12 | class TestAccount(unittest.TestCase): ... class TestCustomer(unittest.TestCase): ... class TestShipping(unittest.TestCase): ... account = TestAccount customer = TestCustomer shipping = TestShipping |
。
你可以打电话
1 | python test.py account |
只有帐户测试,甚至
1 | $ python test.py account customer |
。
对两个病例进行检测
你基本上有两种方法:
我是第二种方法的强烈支持者;单元测试应该只测试一个非常单元的代码,而不是复杂的系统(如数据库或集群)。但我理解这并不总是可能的;有时,创建实体模型太贵了,或者测试的目标确实在复杂的系统中。
回到选项(1),您可以这样继续:
1 2 3 | suite = unittest.TestSuite() suite.addTest(MyUnitTestClass('quickRunningTest')) suite.addTest(MyUnitTestClass('otherTest')) |
然后将套件传递给测试运行程序:
1 | unittest.TextTestRunner().run(suite) |
号
关于python文档的更多信息:http://docs.python.org/library/unittest.html testsuite对象
由于您使用了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | Usage: tests.py [options] [test] [...] Options: -h, --help Show this message -v, --verbose Verbose output -q, --quiet Minimal output -f, --failfast Stop on first failure -c, --catch Catch control-C and display results -b, --buffer Buffer stdout and stderr during test runs Examples: tests.py - run default set of tests tests.py MyTestSuite - run suite 'MyTestSuite' tests.py MyTestCase.testSomething - run MyTestCase.testSomething tests.py MyTestCase - run all 'test*' test methods in MyTestCase |
号
也就是说,你可以
1 | python tests.py TestClass.test_method |
号
我找到了另一个解决方案,基于
基于标签
我想应用一个标记系统,将一些测试标记为
然后运行
实施
我分两部分实现了这一点:
工作实施在此要点中:https://gist.github.com/fragmuffin/a245f59bdcd457936c3b51a2ebb3f6c
(一个充分发挥作用的例子太长了,不能放在这里)
结果是…
1 2 3 4 5 6 7 8 9 10 | $ ./runtests.py --blacklist foo test_foo (test_things.MyTest2) ... ok test_bar (test_things.MyTest3) ... ok test_one (test_things.MyTests1) ... skipped 'label exclusion' test_two (test_things.MyTests1) ... skipped 'label exclusion' ---------------------------------------------------------------------- Ran 4 tests in 0.000s OK (skipped=2) |
。
所有
也可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 | def skipOrRunTest(self,testType): #testsToRun = 'ALL' #testsToRun = 'testType1, testType2, testType3, testType4,...etc' #testsToRun = 'testType1' #testsToRun = 'testType2' #testsToRun = 'testType3' testsToRun = 'testType4' if ((testsToRun == 'ALL') or (testType in testsToRun)): return True else: print"SKIPPED TEST because: \t testSuite '" + testType +"' NOT IN testsToRun['" + testsToRun +"']" self.skipTest("skipppy!!!") |
然后在每个单元测试的开始添加对skiporruntest方法的调用,如下所示:
1 2 | def testType4(self): self.skipOrRunTest('testType4') |
。
我试过了@slott的回答:
1 2 3 | if __name__ =="__main__": suite = eval(sys.argv[1]) # Be careful with this line! unittest.TextTestRunner().run(suite) |
。
但这给了我以下错误:
1 2 3 4 5 6 7 8 | Traceback (most recent call last): File"functional_tests.py", line 178, in <module> unittest.TextTestRunner().run(suite) File"/usr/lib/python2.7/unittest/runner.py", line 151, in run test(result) File"/usr/lib/python2.7/unittest/case.py", line 188, in __init__ testMethod = getattr(self, methodName) TypeError: getattr(): attribute name must be string |
号
以下内容对我很有用:
1 2 3 4 | if __name__ =="__main__": test_class = eval(sys.argv[1]) suite = unittest.TestLoader().loadTestsFromTestCase(test_class) unittest.TextTestRunner().run(suite) |
号
研究使用专用的测试运行程序,比如py.test、nose甚至zope.testing。它们都有用于选择测试的命令行选项。
例如nose:https://pypi.python.org/pypi/nose/1.3.0
我创建了一个修饰器,允许将测试标记为慢测试,并使用环境变量跳过它们。
1 2 3 4 5 | from unittest import skip import os def slow_test(func): return skipIf('SKIP_SLOW_TESTS' in os.environ, 'Skipping slow test')(func) |
现在,您可以将测试标记为慢,如下所示:
1 2 3 | @slow_test def test_my_funky_thing(): perform_test() |
。
并通过设置
1 | SKIP_SLOW_TESTS=1 python -m unittest |
。
这是唯一对我有用的东西。
1 2 | if __name__ == '__main__': unittest.main( argv=sys.argv, testRunner = unittest.TextTestRunner(verbosity=2)) |
当我调用它时,尽管我必须以类和测试名称的名义通过。有点不方便,因为我没有记住班级和考试名称的组合。
python./tests.py类u name.test u 30311
删除类名和测试名将运行文件中的所有测试。我发现这比内置方法更容易处理,因为我没有在cli上真正更改命令。只需添加参数。
享受,基思
以前没有找到一个很好的方法,所以在这里分享。
目标:把一组测试文件放在一起,这样它们就可以作为一个单元运行,但是我们仍然可以选择它们中的任何一个单独运行。
问题:发现方法不允许简单地选择单个测试用例来运行。
设计:见下文。这会使命名空间变平,以便可以按testcase类名选择,并去掉"tests1.test_core"前缀:
1 | ./run-tests TestCore.test_fmap |
号
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | test_module_names = [ 'tests1.test_core', 'tests2.test_other', 'tests3.test_foo', ] loader = unittest.defaultTestLoader if args: alltests = unittest.TestSuite() for a in args: for m in test_module_names: try: alltests.addTest( loader.loadTestsFromName( m+'.'+a ) ) except AttributeError as e: continue else: alltests = loader.loadTestsFromNames( test_module_names ) runner = unittest.TextTestRunner( verbosity = opt.verbose ) runner.run( alltests ) |
号
我找到了另一种选择测试方法的方法,我只想通过向它们添加一个属性来运行这些方法。基本上,您使用一个元类来修饰具有stepDebug属性的testcase类内部的可调用文件,该类使用一个unittest.skip修饰器。有关的详细信息
通过使用decorator和元类跳过python中除一个以外的所有单元测试
我不知道它是否比上面的那些更好的解决方案,我只是作为一个选项提供它。