program tip

Python unittest.TestCase 실행 순서

radiobox 2020. 11. 14. 10:06
반응형

Python unittest.TestCase 실행 순서


Python unittest에서 테스트 케이스가 실행되는 순서를 설정 하는 방법 이 있습니까?

내 현재 TestCase수업에서 일부 테스트 케이스에는 다른 테스트 케이스가 제대로 실행되도록 조건을 설정하는 부작용이 있습니다. 이제이 작업을 수행하는 올바른 방법 setUp()은 모든 설정 실현 작업을 수행하는 데 사용 하는 것임을 깨달았지만, 각 연속 테스트가 다음 테스트에서 사용할 수있는 상태를 약간 더 빌드하는 디자인을 구현하고 싶습니다. 나는 이것이 훨씬 더 우아하다고 생각합니다.

class MyTest(TestCase):
  def test_setup(self):
   #do something
  def test_thing(self)
   #do something that depends on test_setup()

이상적으로는 테스트가 수업에 나타나는 순서대로 실행되기를 바랍니다. 알파벳 순서로 실행되는 것으로 보입니다.


독립적 인 테스트를하지 마십시오. 모 놀리 식 테스트를 원한다면 모 놀리 식 테스트를 작성하십시오.

class Monolithic(TestCase):
  def step1(self):
      ...

  def step2(self):
      ...

  def _steps(self):
    for name in dir(self): # dir() result is implicitly sorted
      if name.startswith("step"):
        yield name, getattr(self, name) 

  def test_steps(self):
    for name, step in self._steps():
      try:
        step()
      except Exception as e:
        self.fail("{} failed ({}: {})".format(step, type(e), e))

나중에 테스트가 실패하기 시작하고 첫 번째 실패한 단계에서 테스트 케이스를 중지하는 대신 실패한 모든 단계에 대한 정보를 원하는 경우 https://docs.python.org/3/library/unittest.html#subtests 기능을 사용할 수 있습니다 . 구분 테스트 반복 사용 하위 테스트

(하위 테스트 기능은 unittest2Python 3.4 이전 버전에서 사용할 수 있습니다 : https://pypi.python.org/pypi/unittest2 )


그러한 기대에 대해 항상 모 놀리 식 테스트를 작성하는 것이 좋습니다. 그러나 저처럼 바보 같은 친구라면보기 흉한 메서드를 알파벳순으로 작성하여 파이썬 문서 http 에서 언급 한대로 a에서 b까지 정렬되도록 할 수 있습니다. : //docs.python.org/library/unittest.html

다양한 테스트 케이스가 실행되는 순서는 문자열에 대한 기본 제공 순서와 관련하여 테스트 함수 이름을 정렬하여 결정됩니다.

예:

  def test_a_first():
  print "1"
  def test_b_next(): 
  print "2" 
  def test_c_last(): 
  print "3"

http://docs.python.org/library/unittest.html

다양한 테스트 케이스가 실행되는 순서는 문자열에 대한 기본 제공 순서와 관련하여 테스트 함수 이름을 정렬하여 결정됩니다.

따라서 test_setup의 이름에 가장 작은 문자열 값이 있는지 확인하십시오 .

이 동작에 의존해서는 안됩니다. 다른 테스트 함수는 실행 순서와 무관해야합니다. 명시 적으로 주문이 필요한 경우 솔루션은 위의 ngcohlan 답변을 참조하십시오 .


오래된 질문,하지만 난 어떤 관련 질문에 나열되어 있지 않은 또 다른 방법 : 사용TestSuite .

순서를 지정하는 또 다른 방법은 테스트를 unitest.TestSuite. 이것은를 사용하여 테스트가 스위트에 추가되는 순서를 존중하는 것 같습니다 suite.addTest(...). 이것을하기 위해:

  • 하나 이상의 TestCase 하위 클래스를 만듭니다.

    class FooTestCase(unittest.TestCase):
        def test_ten():
            print('Testing ten (10)...')
        def test_eleven():
            print('Testing eleven (11)...')
    
    class BarTestCase(unittest.TestCase):
        def test_twelve():
            print('Testing twelve (12)...')
        def test_nine():
            print('Testing nine (09)...')
    
  • 호출 가능한 시험 스위트 생성을 만들기 원하는 순서에 추가 에서 적응, 워드 프로세서이 질문 :

    def suite():
        suite = unittest.TestSuite()
        suite.addTest(BarTestCase('test_nine'))
        suite.addTest(FooTestCase('test_ten'))
        suite.addTest(FooTestCase('test_eleven'))
        suite.addTest(BarTestCase('test_twelve'))
        return suite
    
  • 테스트 스위트 실행, 예 :

    if __name__ == '__main__':
        runner = unittest.TextTestRunner(failfast=True)
        runner.run(suite())
    

상황에 따라 나는 이것이 필요했고 다른 옵션에 만족하지 않았습니다. 위의 테스트 오더 방식을 정했습니다. 이 TestSuite 메서드가 여러 "단위 테스트 순서 질문"(예 :이 질문 및 실행 순서 , 변경 순서 또는 테스트 순서를 포함한 기타 질문) 중 하나를 나열하는 것을 보지 못했습니다 .


I ended up with a simple solution that worked for me:

class SequentialTestLoader(unittest.TestLoader):
    def getTestCaseNames(self, testCaseClass):
        test_names = super().getTestCaseNames(testCaseClass)
        testcase_methods = list(testCaseClass.__dict__.keys())
        test_names.sort(key=testcase_methods.index)
        return test_names

And then

unittest.main(testLoader=utils.SequentialTestLoader())

Tests which really depend on each other should be explicitly chained into one test.

Tests which require different levels of setup, could also have their corresponding setUp() running enough setup - various ways thinkable.

Otherwise unittest handles the test classes and test methods inside the test classes in alphabetical order by default (even when loader.sortTestMethodsUsing is None). dir() is used internally which sorts by guarantee.

The latter behavior can be exploited for practicability - e.g. for having the latest-work-tests run first to speed up the edit-testrun-cycle. But that behavior should not be used to establish real dependencies. Consider that tests can be run individually via command-line options etc.


@ncoghlan's answer was exactly what I was looking for when I came to this thread. I ended up modifying it to allow each step-test to run, even if a previous step had already thrown an error; this helps me (and maybe you!) to discover and plan for the propagation of error in multi-threaded database-centric software.

class Monolithic(TestCase):
  def step1_testName1(self):
      ...

  def step2_testName2(self):
      ...

  def steps(self):
      '''
      Generates the step methods from their parent object
      '''
      for name in sorted(dir(self)):
          if name.startswith('step'):
              yield name, getattr(self, name)

  def test_steps(self):
      '''
      Run the individual steps associated with this test
      '''
      # Create a flag that determines whether to raise an error at
      # the end of the test
      failed = False

      # An empty string that the will accumulate error messages for 
      # each failing step
      fail_message = ''
      for name, step in self.steps():
          try:
              step()
          except Exception as e:
              # A step has failed, the test should continue through
              # the remaining steps, but eventually fail
              failed = True

              # get the name of the method -- so the fail message is
              # nicer to read :)
              name = name.split('_')[1]
              # append this step's exception to the fail message
              fail_message += "\n\nFAIL: {}\n {} failed ({}: {})".format(name,
                                                                       step,
                                                                       type(e),
                                                                       e)

      # check if any of the steps failed
      if failed is True:
          # fail the test with the accumulated exception message
          self.fail(fail_message)

참고URL : https://stackoverflow.com/questions/5387299/python-unittest-testcase-execution-order

반응형