Programing

Python unittest : 테스트 파일의 일부만 실행하는 방법은 무엇입니까?

crosscheck 2020. 11. 7. 09:02
반응형

Python unittest : 테스트 파일의 일부만 실행하는 방법은 무엇입니까?


꽤 많은 시간이 걸리는 테스트가 포함 된 테스트 파일이 있습니다 (클러스터에 계산을 보내고 결과를 기다립니다). 이들 모두는 특정 TestCase 클래스에 있습니다.

시간이 걸리고 더 이상 중단 될 가능성이 없기 때문에이 테스트 하위 집합이 실행되는지 여부를 선택할 수 있기를 원합니다 (가장 좋은 방법은 명령 줄 인수, 즉 " ./tests.py --offline"또는 그래서 시간이있을 때 대부분의 테스트를 자주, 빠르게, 그리고 전체 세트를 가끔씩 실행할 수있었습니다.

지금 unittest.main()은 테스트를 시작하는 데 사용합니다.

감사.


기본값 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])
    

Fast vs. Slow를 나타내도록 TestCase 이름을 조정했습니다. unittest.TestLoader를 하위 클래스로 분류하여 클래스 이름을 구문 분석하고 여러 로더를 만들 수 있습니다.

그런 다음 메인 프로그램은 optparse 또는 argparse (2.7 또는 3.2부터 사용 가능)를 사용 하여 명령 줄 인수를 구문 분석 하여 실행할 제품군을 빠르게, 느리게 또는 모두 선택할 수 있습니다.

또는 sys.argv[1]세 가지 값 중 하나를 신뢰하고 다음과 같이 간단한 것을 사용할 수 있습니다.

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

단일 특정 테스트 만 실행하려면 다음을 사용할 수 있습니다.

$ python -m unittest test_module.TestClass.test_method

여기에 더 많은 정보


실제로 테스트 케이스의 이름을 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

두 경우 모두 테스트


나는 간단한 사용하여 이것을하고 있습니다 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 …

기본적으로 두 가지 방법이 있습니다.

  1. 클래스에 대한 고유 한 테스트 모음 정의
  2. 실제 데이터를 반환 할 클러스터 연결의 모의 클래스를 만듭니다.

나는 그의 두 번째 접근 방식을 강력하게지지합니다. 단위 테스트 복잡한 시스템 (예 : 데이터베이스 또는 클러스터)이 아닌 코드 단위 만 테스트 해야합니다 . 그러나 나는 그것이 항상 가능한 것은 아니라는 것을 이해합니다. 때로는 모형을 만드는 것이 너무 비싸거나 테스트의 목표가 실제로 복잡한 시스템에 있습니다.

옵션 (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


사용하기 때문에 문서를 얻기 위해 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

또는 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')

unittest.skip데코레이터의 작동 방식에 따라 다른 해결책을 찾았습니다 . 을 설정함으로써 __unittest_skip____unittest_skip_why__.

라벨 기반

I는 몇 가지 테스트 라벨, 라벨링 시스템을 적용하고 싶었 quick, slow, glacier, memoryhog, cpuhog, core, 등을.

그런 다음 all 'quick' tests, 또는 run everything except 'memoryhog' tests, 기본 화이트리스트 / 블랙리스트 설정을 실행합니다.

이행

나는 이것을 두 부분으로 구현했습니다.

  1. 먼저 테스트에 레이블을 추가합니다 (사용자 정의 @testlabel클래스 데코레이터 를 통해 )
  2. unittest.TestRunner건너 뛸 테스트를 식별하고 실행하기 전에 테스트 목록 콘텐츠를 수정하는 사용자 지정 .

작업 구현은이 요점에 있습니다 : https://gist.github.com/fragmuffin/a245f59bdcd457936c3b51aa2ebb3f6c

(a fully working example was too long to put here)

The result being...

$ ./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)

All MyTests1 class tests are skipped because it has the foo label.

--whitelist also works


Look into using a dedicated testrunner, like py.test, nose or possibly even zope.testing. They all have command line options for selecting tests.

Look for example as Nose: https://pypi.python.org/pypi/nose/1.3.0


I tried @slott's answer:

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

But that gave me the following error:

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

The following worked for me:

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

I have found another way to select the test_* methods that I only want to run by adding an attribute to them. You basically use a metaclass to decorate the callables inside the TestCase class that have the StepDebug attribute with a unittest.skip decorator. More info on

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

I don't know if it is a better solution than those above I am just providing it as an option.


Haven't found a nice way to do this before, so sharing here.

Goal: Get a set of test files together so they can be run as a unit, but we can still select any one of them to run by itself.

Problem: the discover method does not allow easy selection of a single test case to run.

Design: see below. This flattens the namespace so can select by TestCase class name, and leave off the the "tests1.test_core" prefix:

./run-tests TestCore.test_fmap

Code

  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 )

This is the only thing that worked for me.

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

When I called it though I had to pass in the name of the class and test name. A little inconvenient since I don't have class and test name combination memorized.

python ./tests.py class_Name.test_30311

Removing the Class name and test name runs all the tests in your file. I find this MUCH more easier to deal with then the built in method since I don't really change my command on the CLI. Just add the parameter.

Enjoy, Keith


I created a decorator that allows for marking tests as slow tests and to skip them using an environment variable

from unittest import skip
import os

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

Now you can mark your tests as slow like this:

@slow_test
def test_my_funky_thing():
    perform_test()

And skip slow tests by setting the SKIP_SLOW_TESTS environment variable:

SKIP_SLOW_TESTS=1 python -m unittest

참고URL : https://stackoverflow.com/questions/1068246/python-unittest-how-to-run-only-part-of-a-test-file

반응형