UnitTest는 JUnit에 영감을 받은 Python 언어의 Unit Testing Framework입니다. 다양한 언어의 주류 Unit Testing Framework와 유사한 스타일을 가지고 있습니다. UnitTest는 자동화 테스트를 지원하며, 테스트 준비와 청소 코드를 재사용하고, 테스트 케이스를 모아 테스트 스크랩으로 만들며, 보고서 생성 프레임워크와 독립적으로 작동합니다.
이러한 기능을 구현하기 위해 UnitTest는 객체지향 방식으로 다음 주요 개념을 지원합니다.
Fixture (테스트 픽처)
Fixture는 하나 이상의 테스트를 수행하기 위해 수행해야 할 준비 작업 및 청소 작업을 의미합니다. 예를 들어 임시 데이터베이스나 프록시 디렉터리 생성, 서버 프로세스 시작 등이 포함될 수 있습니다.
TestCase (테스트 케이스)
테스트 케이스는 특정 입력에 대한 응답을 점검하는 독립적인 테스트 단위입니다. UnitTest는 테스트 케이스를 생성하기 위해 TestCase라는 기본 클래스를 제공합니다.
TestSuite (테스트 스크랩)
테스트 스크랩은 테스트 케이스의 모음이며, 하나 이상의 테스트 케이스, 또는 테스트 스크랩, 또는 이 둘의 조합을 포함할 수 있습니다. 이는 함께 실행할 테스트를 모아おく 데 사용됩니다.
TestRunner (테스트 런너)
테스트 런너는 테스트를 실행하고 결과를 출력하는 컴포넌트입니다. 이 런너는 텍스트 인터페이스, 그래픽 인터페이스, 또는 테스트 실행 결과를 나타내는 특정 값을 반환하는 방식으로 작동할 수 있습니다.
기본 예제
UnitTest 모듈은 테스트를 생성하고 실행하는 도구를 제공합니다. 다음은 이러한 도구의 일부를 보여주는 짧은 코드 예제입니다:
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
with self.assertRaises(TypeError):
s.split(2)
if __name__ == '__main__':
unittest.main()
TestCase 클래스를 상속하면 테스트 케이스를 생성합니다. 위 예제에서는 세 가지 독립적인 테스트가 있습니다. 각 테스트는 test로 시작하는 클래스의 메서드로 정의됩니다.
각 테스트의 핵심은 assertEqual()를 사용하여 예상 결과를 검증하거나, assertTrue()나 assertFalse()를 사용하여 조건을 검증하거나, assertRaises()를 사용하여 특정 예외가 발생하는지 확인합니다. 이러한 방법은 단순히 assert 문구를 사용하는 것보다 테스트 결과 보고서를 생성하는 데 도움이 됩니다.
setUp() 및 tearDown() 메서드를 통해 테스트 시작 전후에 수행할 작업을 설정할 수 있습니다. 더 자세한 내용은 테스트 코드 조직 절에서 설명합니다.
마지막 예제 코드에서 테스트를 실행하는 간단한 방법을 보여줍니다. unittest.main()은 테스트 스크립트의 명령줄 인터페이스를 제공합니다. 이 스크립트를 명령줄에서 실행하면 다음과 같은 출력을 얻을 수 있습니다:
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
명령줄에 -v 매개변수를 추가하면 상세한 정보가 출력됩니다:
test_isupper (__main__.TestStringMethods) ... ok
test_split (__main__.TestStringMethods) ... ok
test_upper (__main__.TestStringMethods) ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.001s
OK
이 예제는 UnitTest에서 가장 많이 사용되는 기능 중 일부를 보여주며, 대부분의 사용자에게 충분할 정도로 간결합니다. 문서의 나머지 부분은 프레임워크의 완전자원을 상세히 설명합니다.
명령줄 인터페이스
UnitTest 모듈은 명령줄에서 모듈, 클래스, 또는 독립적인 테스트 메서드를 실행할 수 있습니다:
python -m unittest test_module1 test_module2
python -m unittest test_module.TestClass
python -m unittest test_module.TestClass.test_method
명령줄에 모듈 경로를 지정할 수도 있습니다:
python -m unittest tests/test_something.py
명령줄에서 다음 옵션을 사용할 수 있습니다:
python -m unittest -v test_module
python -m unittest
python -m unittest -h
더 많은 옵션 및 사용법에 대해 알아보려면 명령줄 옵션 절을 참조하세요.
명령줄 옵션
UnitTest는 다음 옵션을 지원합니다:
-b또는--buffer: 성공한 테스트의 출력을 버퍼링하고, 실패한 테스트에서만 버퍼를 출력합니다.-c또는--catch: Ctrl-C를 누르면 현재 실행 중인 테스트를 완료하고 결과를 보고합니다.-f또는--failfast: 첫 번째 실패 또는 오류를 만날 때 테스트를 중단합니다.-k: 패턴 또는 서브스트링을 기반으로 테스트 메서드나 클래스를 필터링합니다.--locals: 추적 중지에 지역 변수를 포함시킵니다.
더 많은 옵션 및 사용법에 대해 알아보려면 명령줄 옵션 절을 참조하세요.
탐색적 테스트
UnitTest는 3.2 버전부터 탐색적 테스트를 지원합니다. 테스트 모듈이 프로젝트 루트 디렉터리에서 로드될 수 있는 경우에만 사용할 수 있습니다.
탐색적 테스트를 명령줄에서 실행하는 방법은 다음과 같습니다:
cd project_directory
python -m unittest discover
탐색적 테스트는 TestLoader.discover()를 통해 구현됩니다.
테스트 코드 조직
UnitTest의 기본 단위는 TestCase입니다. TestCase는 독립적인 테스트 단위를 나타내며, 특정 조건을 검증하고 정확성을 검증하는 코드를 포함합니다.
독립적인 TestCase 클래스를 만들 때는 TestCase 클래스를 상속해야 합니다:
import unittest
class WidgetTestCase(unittest.TestCase):
def setUp(self):
self.widget = Widget('The widget')
def test_default_widget_size(self):
self.assertEqual(self.widget.size(), (50, 50))
def test_widget_resize(self):
self.widget.resize(100, 150)
self.assertEqual(self.widget.size(), (100, 150))
SetUp() 및 tearDown() 메서드는 각 테스트 실행 전후에 수행할 작업을 정의합니다.SetUp() 메서드가 예외를 발생하면 해당 테스트는 오류로 간주됩니다.
기존 테스트 코드 활용
기존 테스트 함수를 사용하려면 FunctionTestCase 클래스를 사용할 수 있습니다:
def testSomething():
something = makeSomething()
assert something.name is not None
testcase = unittest.FunctionTestCase(testSomething, setUp=makeSomethingDB, tearDown=deleteSomethingDB)
예상 실패 및 건너뛰기
UnitTest는 테스트를 건너뛰거나 예상되는 실패를 처리하는 데도 사용할 수 있습니다:
import unittest
class MyTestCase(unittest.TestCase):
@unittest.skip("demonstrating skipping")
def test_nothing(self):
self.fail("shouldn't happen")
@unittest.skipIf(mylib.__version__ < (1, 3), "not supported in this library version")
def test_format(self):
pass
@unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
def test_windows_support(self):
pass
def test_maybe_skipped(self):
if not external_resource_available():
self.skipTest("external resource not available")
# test code that depends on the external resource
pass
SubTest 사용
3.4 버전부터 SubTest를 통해 테스트 반복을 구분할 수 있습니다:
class NumbersTest(unittest.TestCase):
def test_even(self):
for i in range(0, 6):
with self.subTest(i=i):
self.assertEqual(i % 2, 0)
TestCase 클래스 및 함수
UnitTest의 API를 자세히 설명합니다.
TestCase 클래스
class unittest.TestCase(methodName='runTest')는 테스트 단위를 나타내는 클래스입니다. 이 클래스는 테스트를 실행하고 결과를 보고하는 데 필요한 인터페이스를 제공합니다.
主요약 메서드는 다음과 같습니다:
setUp(): 테스트 픽처를 준비합니다.tearDown(): 테스트 후 청소 작업을 수행합니다.setUpClass(): 클래스 단위 테스트 전에 실행합니다.tearDownClass(): 클래스 단위 테스트 후에 실행합니다.run(result=None): 테스트를 실행하고 결과를 수집합니다.
FunctionTestCase 클래스
class unittest.FunctionTestCase(testFunc, setUp=None, tearDown=None, description=None)는 TestCase 인터페이스의 일부를 구현하며, 기존 함수형 테스트 코드를 통합하기 위해 사용됩니다.
테스트 로더 및 실행
UnitTest는 테스트를 로드하고 실행하는 데 필요한 클래스를 제공합니다.
TestLoader 클래스
class unittest.TestLoader는 테스트를 로드하는 데 사용되는 클래스입니다.
TestResult 클래스
class unittest.TestResult는 테스트 실행 결과를 저장하는 클래스입니다.
TextTestRunner 클래스
class unittest.TextTestRunner는 테스트 결과를 텍스트로 출력하는 실행기를 제공합니다.
로드 테스트 프로토콜
3.2 버전부터 모듈 또는 패키지가 테스트를 로드하는 방법을 自訂할 수 있습니다.