[python] unittest(단위 테스트)

lv2dev·2024년 8월 18일
0

Python 이것저것

목록 보기
5/7

정말 간단하게 정리했다. 자세한건 docs에...

파이썬도 JUnit과 같은 단위 테스트를 할 수 있다. 주로 unittest라는 표준 라이브러리를 사용한다.

import unittest

docs

unittest 모듈의 기본 개념

unittest는 클래스는 단일 테스트 케이스를 정의하는 데 사용된다. 각 테스트 메서드는 반드시 test_로 시작하는 이름을 가져야 하며, 이는 unittest가 테스트 메서드를 자동으로 인식하는 규칙이다.

import unittest

class TestExample(unittest.TestCase):
    
    def test_addition(self):
        self.assertEqual(1 + 1, 2)
        
    def test_subtraction(self):
        self.assertEqual(5 - 3, 2)

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

위 코드에서 TestExample 클래스는 TestCase를 상속받고 있으며, 각 테스트 메서드는 test_로 시작한다. assertEqual 메서드는 두 값이 같은지 확인하는 함수이다. 이 파일을 실행하면 unittest는 자동으로 테스트 메서드를 찾아 실행한다.

unittest의 주요 구성 요소

  1. 테스트 케이스(Test Case)
    테스트 케이스는 코드의 특정 단위(주로 함수나 메서드)를 테스트하는 단위이다. 각 테스트 케이스는 고유한 테스트 시나리오를 나타내며, unittest.Testcase를 상속받아 작성된다.
  2. 테스트 스위트(Test Suite)
    테스트 스위트는 여러 테스트 케이스를 모아놓은 것이다. 이는 서로 관련이 있는 여러 테스트 케이스를 한꺼번에 실행할 수 있도록 도와준다.
def suite():
    suite = unittest.TestSuite()
    suite.addTest(TestExample('test_addition'))
    suite.addTest(TestExample('test_subtraction'))
    return suite
  1. 테스트 러너(Test Runner)
    테스트 러너는 테스트나 테스트 스위트를 실행하고, 그 결과를 출력하는 결과를 출력하는 역할을 한다. 기본적을 unittest.main()이 테스트 러너로 동작하며, 다양한 출력 포맷을 제공하는 테스트 러너를 선택할 수도 있다.
  2. 픽스처(Fixture)
    픽스처는 테스트를 준비하거나 정리하는데 필요한 설정을 뜻한다. 이를 위해 setUp()treeDown() 메서드를 사용한다.
  • setUp(): 각 테스트 메서득 실행되기 전에 실행되며, 테스트를 위한 초기화 작업을 수행한다.
  • tearDown(): 각 테스트 메서드가 실행된 후에 호출되며, 테스트가 끝난 후 정리 작업을 수행한다.
import unittest

class TestExample(unittest.TestCase):

    def setUp(self):
        # 테스트 초기화 코드
        self.number = 10
    
    def tearDown(self):
        # 테스트 종료 후 정리 코드
        pass
    
    def test_multiplication(self):
        self.assertEqual(self.number * 2, 20)

여기서 setUp() 메서드는 테스트가 실행되기 전에 self.number를 10으로 초기화하고, 테스트 메서드 test_multiplicationself.number에 대한 연산을 테스트한다.

unittest의 주요 메서드

unittest에서 제공하는 주요 단연 메서드(Assertion Methods)는 테스트가 기대하는 결과와 실제 결과를 비교합니다. 이러한 메서드를 사용해 테스트 조건을 정의할 수 있다.
1. assertEqual(a, b)
두 값이 동일한지 확인한다.

self.assertEqual(2 + 2, 4)
  1. assertNotQueal(a, b)
    두 값이 동일하지 않은지 확인한다.
self.assertNotEqual(2 + 2, 5)
  1. assertTrue(x)
    xTrue인지 확인한다
self.assertTrue(3 > 2)
  1. assertFalse(x)
    xFalse인지 확인한다.
self.assertFalse(3 < 2)
  1. assertIs(a, b)
    두 변수가 동일한 객체를 가리키고 있는지 확인한다
self.assertIs(a, b)
  1. assertIsNone(x)
    값이 None인지 확인합니다.
self.assertIsNone(None)
  1. assertIn(a, b)
    ab에 포함되는지 확인한다.
self.assertIn(3, [1, 2, 3])
  1. assertRaises(exception, callable, *args, **kwargs)
    특정 예외가 발생하는지를 확인한다.
with self.assertRaises(ZeroDivisionError):
    1 / 0

테스트 실행과 출력

unittest는 터미널에서 실행할 수 있으며, 실행 결과는 성공, 실패 또는 에러로 구분된다.

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

위의 코드로 테스트 파일을 실행하면, 테스트 러너가 각 테스트 케이스를 실행한 후 결과를 출력한다. 일반적으로 다음과 같은 형식의 출력이 제공된다.

  • .: 테스트가 성공적으로 실행됨
  • F: 테스트 실패
  • E: 테스트 실행 중 예외가 발생함

테스트 스킵 및 조건부 실행

때로는 특정 조건에서 테스트를 건너뛰거나, 조건부로 테스트를 실행해야 할 때가 있다.
unittest는 이를 위해 skip 데코레이터와 메서드를 제공한다.

  1. @unittest.skip(reason)
    테스트를 무조건 건너뛴다.
@unittest.skip("이 테스트는 건너뜁니다.")
def test_skipped(self):
    self.assertEqual(1, 1)
  1. @unittest.skipIf(condition, reason)
    조건이 참일 경우 테스트를 건너뛴다.
@unittest.skipIf(sys.platform == "win32", "윈도우에서 실행 안 함")
def test_not_on_windows(self):
    self.assertEqual(1, 1)
  1. @unittest.expectedFailure
    테스트가 실패할 것으로 예상되는 경우, 이를 명시한다. 테스트가 실패해도 전체 테스트 결과에 영향을 주지 않는다.
@unittest.expectedFailure
def test_will_fail(self):
    self.assertEqual(1, 2)

테스트 더블 (Mock 객체)

때때로 실제 객체가 아니라 테스트를 위해 가짜 객체를 사용해야 할 필요가 있다. 이를 위해 파이썬은 unittest.mock 모듈을 제공한다. mock 객체는 외부 의존성을 제거하고 코드의 일부만을 테스트하는데 유용하다.

mock 사용 예시

from unittest.mock import MagicMock

class ProductionClass:
    def method(self):
        pass

mock = MagicMock()
mock.method.return_value = 3
print(mock.method())  # 출력: 3

여기서 MagicMock 객체는 원래 메서드를 호출하는 대신, 사전에 정의된 값을 반환한다.

파라미터화된 테스트

테스트를 반복해서 다른 입력값으로 실행해야 할 경우, 파라미터화된 테스트가 유용합니다. 기본적으로 unittest는 파라미터화된 테스트를 직접 지원하지 않지만, unittesst 확장 라이브러리인 parameterized와 같은 라이브러리를 사용하면 쉽게 구현할 수 있다.

from parameterized import parameterized

class TestParameterized(unittest.TestCase):
    
    @parameterized.expand([
        ("case1", 1, 2, 3),
        ("case2", 2, 3, 5),
    ])
    def test_addition(self, name, a, b, expected):
        self.assertEqual(a + b, expected)

위 예시에서 parameterized.expand() 데코레이터는 각 테스트 케이스에 다른 매개변수를 전달하여 동일한 테스트를 반복적으로 실행한다.

profile
언제나 레벨업을 하고 싶은 영원한 lv1

0개의 댓글