728x90
반응형

파이썬 테스트  Frame Work 종류와 장단점 및 간단한 사용 방법에 대해 설명 합니다. 

 

파이썬 테스트 프레임워크 (Python Test FrameWork)

  • 파이썬 에서 테스트 자동화를 위해 사용하는 테스트 Frame work 는 아래 리스트와 같다 
  • 일반적으로 가장 널리 사용 하는 pytestUnittest 기능과 간단한 동작을 할수 있는 예제를 다루겠습니다. 
프레임워크 주요 특징 사용 대상
Pytest 간결한 assert, 강력한 Fixture, 풍부한 플러그인 생태계
모든 파이썬 프로젝트 (가장 강력히 추천)
Unittest 파이썬 표준 라이브러리, 별도 설치 불필요, 객체지향 구조
외부 라이브러리 의존성을 최소화해야 하는 경우, 레거시 프로젝트
robot framework 키워드 기반 테스트
비개발자 친화적, GUI 자동화 + API 테스트 통합 가능
Doctest 문서 내 예제 코드를 테스트로 활용
라이브러리 문서의 예제 코드 검증
Behave BDD(행위 주도 개발) 스타일, 자연어 시나리오
기획자/비개발자와 테스트 시나리오를 공유해야 하는 프로젝트

 

pytest 

 

  • 간결한 문법: assert만 써도 검증 가능
  • 다양한 플러그인: HTML 리포트, 병렬 실행 등
  • pytest.mark로 범위/조건 제어 가능
  • 공식 문서는 아래 사이트에서 확인 할 수 있다.

pytest 프레임워크 구조 

Pytest는 전통적인 단위 테스트 프레임워크와 달리, 명시적인 TestCase 클래스 상속 없이도 테스트를 작성할 수 있게 해줍니다. 핵심 구조는 다음과 같습니다.

  • 테스트 함수 (Test Functions): Pytest는 test_*로 시작하는 모든 함수를 테스트로 인식합니다. 가장 기본적인 테스트 단위이며, 별도의 클래스나 상속 없이도 작동합니다.
  • 테스트 모듈 (Test Modules): test_*로 시작하는 파일(test_example.py, my_module_test.py 등) 내에 있는 테스트 함수들을 자동으로 찾아서 실행합니다.
  • 테스트 클래스 (Test Classes): 선택 사항이지만, 여러 테스트 함수를 그룹화하고 싶을 때 Test로 시작하는 클래스 안에 test_로 시작하는 메서드를 정의할 수 있습니다. 다만, unittest.TestCase를 상속받을 필요는 없습니다.
  • 픽스처 (Fixtures): 테스트를 실행하기 전후에 필요한 설정(setup) 및 해제(teardown) 작업을 수행하는 함수입니다. @pytest.fixture 데코레이터를 사용하여 정의하며, 테스트 함수에서 인자로 요청하면 자동으로 주입됩니다. unittest의 setUp/tearDown보다 훨씬 유연하고 강력한 기능을 제공합니다.
  • conftest.py 파일: 여러 테스트 파일에서 공유되는 픽스처나 훅(hook) 함수를 정의하는 데 사용됩니다. 이 파일은 pytest가 테스트를 찾을 때 자동으로 인식하며, 해당 디렉토리 및 하위 디렉토리의 모든 테스트에서 픽스처를 사용할 수 있게 합니다.
  • 플러그인 (Plugins): Pytest는 풍부한 플러그인 생태계를 가지고 있습니다. 코드 커버리지, HTML 리포트 생성, 분산 테스트 실행 등 다양한 기능을 플러그인을 통해 확장할 수 있습니다.

 

pytest 클래스 및 함수 호출 관계 및 순서

  • 함수 기반 테스트 흐름
test_파일.py
   │
   ├── def test_func():
   │       ├── pytest fixture 실행 (선택)
   │       ├── 테스트 실행
   │       └── cleanup 수행

 

  • 클래스 기반 테스트 흐름
TestClass:
    ├── @pytest.fixture(scope="class") → 클래스 전후
    ├── setup_method() → 각 test 함수 전
    ├── test_xxx() → 테스트 함수
    ├── teardown_method() → 각 test 함수 후

 

  • Pytest는 테스트를 발견하고 실행하는 과정에서 unittest와는 다른 접근 방식을 취합니다. setUp/tearDown 대신 픽스처를 통해 초기화 및 정리 작업을 관리하며, 이는 훨씬 유연한 제어를 가능하게 합니다.
  • 테스트 발견 (Test Discovery)
    • Pytest는 기본적으로 다음 규칙에 따라 테스트를 자동으로 찾아냅니다.
      • test_*.py 또는 *_test.py 패턴을 따르는 파일.
      • 이러한 파일 내에서 test_로 시작하는 함수.
      • Test로 시작하는 클래스 내에서 test_로 시작하는 메서드 (상속 불필요).
  • 실행 순서 및 픽스처 호출
  • Pytest는 테스트를 실행할 때, 각 테스트 함수가 필요로 하는 픽스처를 자동으로 감지하고 주입합니다. 픽스처는 정의된 스코프(scope) 에 따라 호출 시점과 정리 시점이 달라집니다.
  • 픽스처의 스코프는 다음과 같습니다
    • function (기본값): 각 테스트 함수가 실행될 때마다 픽스처가 호출되고, 테스트 함수가 끝난 후에 정리됩니다. (가장 일반적인 setUp/tearDown과 유사)
    • class: 해당 클래스 내의 모든 테스트 메서드가 실행되기 전에 한 번 호출되고, 클래스 내 모든 테스트가 끝난 후에 정리됩니다.
    • module: 해당 모듈 내의 모든 테스트가 실행되기 전에 한 번 호출되고, 모듈 내 모든 테스트가 끝난 후에 정리됩니다.
    • session: 전체 테스트 세션이 시작되기 전에 한 번 호출되고, 모든 테스트가 끝난 후에 정리됩니다. (가장 넓은 스코프)

호출 관계 및 순서 (픽스처 포함):

  1. 테스트 세션 시작: pytest 명령 실행
  2. session 스코프 픽스처 호출: 정의되어 있다면 가장 먼저 호출됩니다.
  3. 각 테스트 모듈 진입:
    • module 스코프 픽스처 호출: 해당 모듈의 테스트가 시작되기 전에 호출됩니다.
    • 각 테스트 클래스 진입 (선택 사항):
      • class 스코프 픽스처 호출: 해당 클래스의 테스트가 시작되기 전에 호출됩니다.
      • 각 test_ 메서드 실행:
        • function 스코프 픽스처 호출: 각 test_ 메서드가 실행되기 전에 호출됩니다.
        • 실제 test_ 메서드 실행: 테스트 로직이 수행됩니다.
        • function 스코프 픽스처 정리: test_ 메서드가 끝난 후에 정리됩니다.
      • class 스코프 픽스처 정리: 해당 클래스의 모든 테스트가 끝난 후에 정리됩니다.
    • module 스코프 픽스처 정리: 해당 모듈의 모든 테스트가 끝난 후에 정리됩니다.
  4. session 스코프 픽스처 정리: 모든 테스트 세션이 끝난 후에 정리됩니다.

이러한 픽스처 메커니즘은 테스트 간의 의존성을 줄이고, 재사용 가능한 설정/해제 코드를 작성하는 데 매우 효과적입니다.

pytest 테스트 사용 예제 

  • pytest test FrameWork 는 파이썬에서 기본 제공 하는 모듈이 아님니다. 
  • pip install pytest 를 통해 pytest 를 설치 합니다. 
pip install pytest
  • pytest_example.py 
import pytest

@pytest.fixture
def sample_data():
    print("\n[SETUP] Fixture 실행")
    return {"a": 1, "b": 2}

def setup_module(module):
    print("\n[SETUP_MODULE] 모듈 레벨 초기화")

def teardown_module(module):
    print("\n[TEARDOWN_MODULE] 모듈 종료 처리")

def setup_function(function):
    print(f"[SETUP_FUNCTION] 함수 {function.__name__} 시작")

def teardown_function(function):
    print(f"[TEARDOWN_FUNCTION] 함수 {function.__name__} 종료")

def test_add(sample_data):
    print("→ 실행: test_add")
    assert sample_data["a"] + sample_data["b"] == 3

def test_sub(sample_data):
    print("→ 실행: test_sub")
    assert sample_data["b"] - sample_data["a"] == 1

 

  • 테스트 결과 
  • -v , -s , --html=report.html 옵션을 통해 테스트 사용법을 익혀 보길 바랍니다. 
    • -v: verbose
    • -s: 표준 출력 표시
    • --html=report.html: HTML 리포트 생성 (pytest-html 필요):
      • pip install pytest-html 

  • pytest pytest_example.py -v -s --html=report.html 실행하면 프로젝트 에 report.html 파일이 생성 된다. 

 

 

pytest 테스트 사용 (conftest.py 적용)

  • conftest.py 설정을 통해 여러 테스트에서 공통으로 사용하는 fixture 를 공유 할수 있도록 케이스를 조금 변경 하겠습니다.
    • conftest.py (샘플데이터를 설정)
import pytest

@pytest.fixture
def sample_data():
    print("\n[SETUP] Fixture 실행")
    return {"a": 1, "b": 2}
  • pytest_example_conftest_test.py (테스트 용 예제)
import pytest

def setup_module(module):
    print("\n[SETUP_MODULE] 모듈 레벨 초기화")

def teardown_module(module):
    print("\n[TEARDOWN_MODULE] 모듈 종료 처리")

def setup_function(function):
    print(f"[SETUP_FUNCTION] 함수 {function.__name__} 시작")

def teardown_function(function):
    print(f"[TEARDOWN_FUNCTION] 함수 {function.__name__} 종료")
    
def test_add(sample_data):
    print("→ 실행: test_add")
    assert sample_data["a"] + sample_data["b"] == 3

def test_sub(sample_data):
    print("→ 실행: test_sub")
    assert sample_data["b"] - sample_data["a"] == 2

 

  • 실행결과
    • conftest.py  에 정의된 샘플데이터를 불러와서 pytest_example_conftest_test.py 에서 테스트슬 수행 하게 된다.
    • 테스트 결과 1건 성공 , 1건 실패로 테스트 출력 결과를 확인 할수 있으며
    • html 옵션을 사용할 경우 html 로 테스트 수행 결과를 보다 가시성 있게 확인이 가능 하다. 
    •  

unittest

 

  • Python 내장 테스트 프레임웍으로 별도 설치는 필요가 없고 파이썬만 설치되어 있으면 바로 사용할 수 있다. 
  • Java의 JUnit과 유사한 구조를 가진다.
  • xUnit 스타일: TestCase 클래스를 상속받아 테스트를 작성하며, assertEqual(), assertTrue() 등 다양한 assert 메서드를 제공합니다.
  • 전통적인 구조: 객체지향 프로그래밍에 익숙한 개발자에게 친숙한 구조를 가집니다.
  • 파이썬 unittest 모듈 공식 문서는 아래 사이트에서 확인 할수 있다. 
 

unittest — Unit testing framework

Source code: Lib/unittest/__init__.py(If you are already familiar with the basic concepts of testing, you might want to skip to the list of assert methods.) The unittest unit testing framework was ...

docs.python.org

Unittest 프레임워크 구조

  • Unittest 에서 주요하게 사용되는 클래스는 다음과 같다. 
    • unittest.TestCase: 테스트의 기본 단위입니다. 각 테스트 케이스는 하나 이상의 테스트 메서드를 포함하며, 이 메서드들은 test_로 시작합니다.
    • unittest.TestSuite: 여러 개의 TestCase나 TestSuite를 묶어서 한꺼번에 실행할 수 있게 해주는 클래스입니다.
    • unittest.TestLoader: TestCase 클래스에서 테스트 메서드를 자동으로 찾아서 TestSuite 객체로 만들어 주는 역할을 합니다.
    • unittest.TestRunner: TestSuite를 실행하고 결과를 보여주는 클래스입니다. 일반적으로 unittest.main() 함수가 이 역할을 대신 수행합니다.

Unittest 클래스 및 함수 호출 관계 및 순서

  • 호출 되는 흐름은 아래 그림과 같다.

 

  • 클래스 단위: TestSuite가 테스트를 시작하면, 각 TestCase 클래스에 대해 다음 메서드가 호출됩니다.
    • setUpClass(): 테스트 클래스 내의 모든 테스트 메서드가 실행되기 전에 단 한 번만 호출됩니다. 클래스 전체에 필요한 초기화 작업을 수행합니다.
    • tearDownClass(): 테스트 클래스 내의 모든 테스트 메서드가 실행된 후에 단 한 번만 호출됩니다. 클래스 단위의 정리 작업을 수행합니다.
  • 테스트 메서드 단위: TestSuite는 각 TestCase 클래스 내의 test_로 시작하는 각 테스트 메서드에 대해 다음 순서대로 메서드를 호출합니다.
    • setUp(): 각 테스트 메서드가 실행되기 전에 호출됩니다. 각 테스트가 독립적으로 동작하도록 초기화하는 역할을 합니다.
    • test_...(): 실제 테스트 로직이 담긴 메서드가 실행됩니다.
    • tearDown(): 각 테스트 메서드가 실행된 후에 호출됩니다. setUp()에서 할당된 리소스를 해제하는 정리 작업을 수행합니다.

 

Unittest 테스트 예제 

import unittest

class MyTest(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        print("setUpClass")

    def setUp(self):
        print("  setUp")

    def test_add(self):
        print("    test_add")
        self.assertEqual(1 + 1, 2)

    def test_sub(self):
        print("    test_sub")
        self.assertEqual(5 - 3, 2)

    def tearDown(self):
        print("  tearDown")

    @classmethod
    def tearDownClass(cls):
        print("tearDownClass")

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

 

 

 

  • 순서 호출 메서드 설명
1 setUpClass() 클래스 전체 테스트 전에 한 번 실행
2 setUp() 각 테스트 메서드 전에 매번 실행
3 test_*() 실제 테스트 실행
4 tearDown() 각 테스트 메서드 후에 매번 실행
5 tearDownClass() 클래스 테스트 후 한 번 실행
728x90
반응형

+ Recent posts