Python unittest:如何只运行部分测试文件?

时间:2009-07-01 09:40:33

标签: python unit-testing python-unittest

我有一个测试文件,其中包含花费大量时间的测试(他们将计算发送到集群并等待结果)。所有这些都在特定的TestCase类中。

由于它们需要时间而且不太可能破坏,我希望能够选择是否运行这个测试子集(最好的方法是使用命令行参数,即“ ./tests.py --offline“或类似的东西”,所以我可以经常快速地运行大部分测试,并在我有时间的情况下偶尔运行整个测试。

目前,我只是使用unittest.main()开始测试。

感谢。

16 个答案:

答案 0 :(得分:80)

要运行一个特定的测试,您可以使用:

$ python -m unittest test_module.TestClass.test_method

更多信息here

答案 1 :(得分:50)

默认的unittest.main()使用默认的测试加载程序从运行main的模块中生成TestSuite。

您不必使用此默认行为。

例如,您可以制作三个unittest.TestSuite个实例。

  1. “快速”子集。

    fast = TestSuite()
    fast.addTests( TestFastThis )
    fast.addTests( TestFastThat )
    
  2. “慢”子集。

    slow = TestSuite()
    slow.addTests( TestSlowAnother )
    slow.addTests( TestSlowSomeMore )
    
  3. “整体”集。

    alltests = unittest.TestSuite([fast, slow])
    
  4. 请注意,我已调整TestCase名称以指示快速与慢速。你可以继承 unittest.TestLoader用于解析类的名称并创建多个加载器。

    然后您的主程序可以使用optparseargparse(自2.7或3.2以来可用)解析命令行参数,以选择要运行的套件,快速,慢速或全部。

    或者,您可以相信sys.argv[1]是三个值之一,并使用像这样简单的东西

    if __name__ == "__main__":
        suite = eval(sys.argv[1])  # Be careful with this line!
        unittest.TextTestRunner().run(suite)
    

答案 2 :(得分:10)

实际上,可以将测试用例的名称作为sys.argv传递,并且只测试那些情况。

例如,假设你有

class TestAccount(unittest.TestCase):
    ...

class TestCustomer(unittest.TestCase):
    ...

class TestShipping(unittest.TestCase):
    ...

account = TestAccount
customer = TestCustomer
shipping = TestShipping

你可以打电话

python test.py account

只进行帐户测试,甚至是

$ python test.py account customer

测试两个案例

答案 3 :(得分:9)

我使用简单的skipIf

进行此操作
import os

SLOW_TESTS = int(os.getenv('SLOW_TESTS', '0'))

@unittest.skipIf(not SLOW_TESTS, "slow")
class CheckMyFeature(unittest.TestCase):
    def runTest(self):
        …

这样我只需用这一行来装饰已经存在的测试用例(不需要创建测试套件或类似的,只需要在我的单元测试文件的开头创建一个os.getenv()调用行),并且默认情况下会跳过此测试。

如果我想尽快执行它,我只需要调用我的脚本:

SLOW_TESTS=1 python -m unittest …

答案 4 :(得分:8)

你基本上有两种方法可以做到:

  1. 为班级
  2. 定义自己的测试套件
  3. 创建将返回实际数据的群集连接的模拟类。
  4. 我是他第二种方法的坚定支持者;单元测试应该只测试一个非常单元的代码,而不是复杂的系统(如数据库或集群)。但我明白并非总是可行;有时,创建模型太昂贵了,或者测试的目标确实在复杂的系统中。

    返回选项(1),您可以这样做:

    suite = unittest.TestSuite()
    suite.addTest(MyUnitTestClass('quickRunningTest'))
    suite.addTest(MyUnitTestClass('otherTest'))
    

    然后将套件传递给测试运行器:

    unittest.TextTestRunner().run(suite)
    

    有关python文档的更多信息:http://docs.python.org/library/unittest.html#testsuite-objects

答案 5 :(得分:6)

由于您使用unittest.main(),因此您只需运行python tests.py --help即可获取文档:

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

也就是说,你可以简单地做到

python tests.py TestClass.test_method

答案 6 :(得分:2)

或者您可以使用unittest.SkipTest()功能。例如,将skipOrRunTest方法添加到测试类中,如下所示:

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:\n\t testSuite '" + testType  + "' NOT IN testsToRun['" + testsToRun + "']" 
        self.skipTest("skipppy!!!")

然后在每个单元测试的最开头添加对此skipOrRunTest方法的调用,如下所示:

def testType4(self):
    self.skipOrRunTest('testType4')

答案 7 :(得分:2)

我找到了另一种解决方案,基于unittest.skip装饰器的工作原理。 通过设置__unittest_skip____unittest_skip_why__

<强>基于标签的

我想应用标签系统,将某些测试标记为quickslowglaciermemoryhogcpuhog,{{1}等等。

然后运行coreall 'quick' tests您的基本白名单/黑名单设置

<强>实施

我分两部分实现了这个:

  1. 首先向测试添加标签(通过自定义run everything except 'memoryhog' tests类装饰器)
  2. 自定义@testlabel以确定要跳过哪些测试,并在执行前修改测试列表内容。
  3. 工作实施在这个要点: https://gist.github.com/fragmuffin/a245f59bdcd457936c3b51aa2ebb3f6c

    (一个完整的例子太长了,无法放在这里)

    结果是......

    unittest.TestRunner

    所有$ ./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) 类测试都会被跳过,因为它有MyTests1标签。

    foo也有效

答案 8 :(得分:1)

使用专用的testrunner,比如py.test,nose或者甚至zope.testing。它们都有用于选择测试的命令行选项。

查看示例为Nose:https://pypi.python.org/pypi/nose/1.3.0

答案 9 :(得分:1)

我试过@slott的回答:

if __name__ == "__main__":
    suite = eval(sys.argv[1])  # Be careful with this line!
    unittest.TextTestRunner().run(suite)

但是这给了我以下错误:

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

以下对我有用:

if __name__ == "__main__":
    test_class = eval(sys.argv[1])
    suite = unittest.TestLoader().loadTestsFromTestCase(test_class)
    unittest.TextTestRunner().run(suite)

答案 10 :(得分:0)

我找到了另一种方法来选择我只想通过向它们添加属性来运行的test_ *方法。您基本上使用元类来装饰TestCase类中具有带有unittest.skip装饰器的StepDebug属性的可调用对象。有关

的更多信息

Skipping all unit tests but one in Python by using decorators and metaclasses

我不知道它是否比上述更好的解决方案我只是提供它作为选项。

答案 11 :(得分:0)

之前没有找到一个很好的方法,所以在这里分享。

目标:将一组测试文件放在一起,以便它们可以作为一个单元运行, 但我们仍然可以选择其中任何一个单独运行。

问题:discover方法不允许轻松选择要运行的单个测试用例。

设计:见下文。这个展平命名空间,因此可以通过TestCase类名选择,并且不使用“tests1.test_core”前缀:

./run-tests TestCore.test_fmap

代码

  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 )

答案 12 :(得分:0)

这是唯一对我有用的东西。

if __name__ == '__main__':
unittest.main( argv=sys.argv, testRunner = unittest.TextTestRunner(verbosity=2))

当我调用它时,我必须传入类的名称和测试名称。有点不方便,因为我没有记住课堂和考试名称的组合。

python ./tests.py class_Name.test_30311

删除类名和测试名会运行文件中的所有测试。我觉得这更容易处理内置方法因为我没有真正改变我在CLI上的命令。只需添加参数。

享受, 基思

答案 13 :(得分:0)

我创建了一个装饰器,该装饰器允许将测试标记为慢速测试,并使用环境变量将其跳过

from unittest import skip
import os

def slow_test(func):
    return skipIf('SKIP_SLOW_TESTS' in os.environ, 'Skipping slow test')(func)

现在您可以像这样将测试标记为缓慢:

@slow_test
def test_my_funky_thing():
    perform_test()

并通过设置SKIP_SLOW_TESTS环境变量来跳过慢速测试:

SKIP_SLOW_TESTS=1 python -m unittest

答案 14 :(得分:0)

我发现这个答案试图弄清楚如何只运行特定的测试;例如,

class TestCase1(unittest.TestCase):
    def some_test(self):
        self.assertEqual(True, True)

class TestCase2(unittest.TestCase):
    def some_other_test(self):
        self.assertEqual(False, False)

我想要一种快速注释掉 TestCase1TestCase2 的方法,而不需要我扫选 100 多行代码,最终我找到了这个:

if __name__ == "__main__":
    tests = []
    tests.append("TestCase1")
    # tests.append("TestCase2")
    unittest.main(defaultTest=tests)

它只是使用 unittest.main()defaultTest 参数来指定要运行的测试类。

答案 15 :(得分:0)

有时我会手动运行每个测试功能。假设我的测试类看起来像这样...

class TestStuff(unittest.TestCase):
    def test1():
    def test2():

然后我运行这个...

t = TestStuff()
t.test1()
t.test2()

(我使用 Spyder IDE 进行数据分析,这对于具有更灵活的测试工具的 IDE 来说可能不太理想)