unittest에서 runTest()로 기본 테스트 메서드 제공하기

공식 문서의 테스트 케이스 관련 설명입니다:

  • 테스트 코드 구성: https://docs.python.org/zh-cn/3.11/library/unittest.html#organizing-test-code
    • 단위 테스트의 기본 구성 요소는 테스트 케이스(test cases)입니다. 이는 실행 조건과 정확성 검사를 포함하는 독립적인 시나리오입니다.
    • unittest에서 테스트 케이스는 unittest.TestCase 인스턴스로 표현됩니다. TestCase의 서브클래스를 작성하거나 FunctionTestCase를 사용하여 직접 테스트 케이스를 만들 수 있습니다.
    • TestCase 인스턴스의 테스트 코드는 완전히 자립적이어야 하므로, 단독으로 실행되거나 다른 테스트 케이스와 임의로 조합되어 실행될 수 있습니다.
    • TestCase의 가장 간단한 서브클래스는 특정 테스트 코드를 실행하기 위해 테스트 메서드(예: test로 시작하는 이름의 메서드)를 하나 이상 구현해야 합니다.
  • TestCase: https://docs.python.org/zh-cn/3.11/library/unittest.html#unittest.TestCase
    • TestCase 클래스의 인스턴스는 unittest 세계에서 논리적 테스트 단위를 나타냅니다. 이 클래스는 기본 클래스로 사용되도록 설계되었으며, 특정 테스트는 이를 상속한 서브클래스에서 구현됩니다. 이 클래스는 테스트 실행에 필요한 인터페이스를 제공하여 테스트를 구동하고, 테스트 코드가 다양한 실패 유형을 감지하고 보고할 수 있는 메서드를 구현합니다.
    • TestCase 인스턴스는 하나의 기본 메서드, 즉 methodName이라는 메서드를 실행합니다. 대부분의 TestCase 사용 시나리오에서는 methodName을 수정하거나 기본 runTest() 메서드를 다시 구현할 필요가 없습니다.
    • 버전 3.2부터 변경: TestCase는 인스턴스화에 methodName을 제공할 필요가 없습니다.

Unittest의 테스트 케이스에는 두 가지 유형의 테스트 메서드가 포함될 수 있습니다:

  • test 접두사로 시작하는 사용자 정의 테스트 메서드 (예: def test_xxxx())
    • 이름만으로 테스트 대상과 목적을 직관적으로 파악할 수 있습니다.
  • 기본 테스트 메서드: runTest()
    • 이는 unittest 프레임워크에서 제공하는 기본 테스트 메서드 명명 규약입니다. 테스트 케이스를 인스턴스화할 때 테스트 메서드를 지정하지 않으면 이 기본 테스트 메서드가 실행됩니다.
    • 테스트 실행의 유연성을 강조합니다.
  • 기타 명명 규약:
    • 테스트 모듈 이름: test_xxxx.py
    • 테스트 케이스(클래스) 이름: class TestXxxx(unittest.TestCase)
    • 테스트 메서드 이름: def test_xxxx(), def runTest()

TestCase 클래스의 소스 코드를 살펴보겠습니다:

  • 생성자(constructor)는 기본 테스트 메서드 이름으로 "runTest"를 도입합니다. 따라서 테스트 케이스 인스턴스를 생성할 때 테스트 메서드 이름을 제공하지 않아도 됩니다.
  • 하지만 존재하지 않는 테스트 메서드 이름을 제공하고 runTest 메서드도 구현하지 않으면, 인스턴스화 시 오류가 발생합니다.
# ..\Python311\Lib\unittest\case.py
class TestCase(object):
    # 기본적으로 테스트 코드 자체는 'runTest'라는 메서드에 배치되어야 합니다.
    # By default, the test code itself should be placed in a method named 'runTest'.

    # 생성자에서 기본 메서드 이름을 제공합니다.
    def __init__(self, methodName='runTest'):
        self._testMethodName = methodName
        ......
        try:
            testMethod = getattr(self, methodName)
        except AttributeError:
            if methodName != 'runTest':
                # 명시적인 메서드 이름 없이 인스턴스화는 허용하지만,
                # *잘못되었거나* 누락된 메서드 이름은 허용하지 않습니다.
                raise ValueError("no such test method in %s: %s" % (self.__class__, methodName))
        ......
        
    def run(self, result=None):
        ...
        testMethod = getattr(self, self._testMethodName)
        ...
        self._callTestMethod(testMethod)

따라서 테스트 케이스에 runTest 메서드를 작성하여 기본 테스트를 수행할 수 있습니다. 실행 시 "테스트 메서드 이름"을 명시적으로 입력하여 특정 테스트를 지정하거나, 아무 메서드 이름도 전달하지 않으면 기본 테스트가 실행되어 테스트가 더욱 유연해집니다.

import unittest

class SampleTest01(unittest.TestCase):
    def test_add(self):
        self.assertEqual(1, 1)

    def test_truthy(self):
        self.assertTrue(1)

    def runTest(self):
        self.assertIn(6, [6, 7, 8])


if __name__ == '__main__':
    test_suite = unittest.TestSuite()
    # 특정 테스트 메서드 실행: 메서드 이름을 인자로 전달
    test_suite.addTests((SampleTest01("test_add"), SampleTest01("test_truthy")))
    # 기본 테스트 메서드 실행: 인자 없이 인스턴스화
    test_suite.addTest(SampleTest01())
    test_runner = unittest.TextTestRunner(verbosity=2)
    test_runner.run(test_suite)

실행 결과:

test_add (__main__.SampleTest01) ... ok
test_truthy (__main__.SampleTest01) ... ok
runTest (__main__.SampleTest01) ... ok

----------------------------------------------------------------------
Ran 3 tests in 0.002s

OK

물론 (설계의 합리성을 고려하지 않더라도) 비즈니스 클래스에 직접 자체 테스트 메서드를 추가할 수도 있습니다:

import unittest

# 비즈니스 클래스 (TestCase 상속)
class OrderManager(unittest.TestCase):
    def get_order(self):
        return "8899776655"
        
    # 자체 테스트 메서드 추가
    def runTest(self):
        order_no = OrderManager().get_order()
        self.assertEqual(order_no, "8899776655")


if __name__ == '__main__':
    unittest.main(verbosity=2)

실행 결과:

runTest (__main__.OrderManager) ... ok

----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

태그: unittest TestCase runTest Python testing Test Framework

8월 6일 13:56에 게시됨