Pytest

[Python] pytest 테스트 자동화 - 픽스처(Fixture) 함수 사용하기

오예남 2025. 2. 5. 22:30

 

 

이전 글에서는 pytest를 이용하여 샘플로 만든 Accumulator 클래스로 단위 테스트를 진행하는 방법을 알아보았습니다.

 

 

[Python] pytest 테스트 자동화 - 단위 테스트(class) 샘플 예제

이전 글에서는 pytest.mark.parametrize 데코레이터를 사용하여 매개변수화하는 방법을 알아보았습니다.  [Python] pytest 테스트 자동화 - parametrize 매개변수화이전 글에서는 pytest.raises 를 사용하여 테스

ohyenam.tistory.com

 

오늘은 pytest의 핵심기능인 Fixture 기능을 이해하고 샘플코드를 작성해보겠습니다.

 


Fixture 함수 이해하기

Fixture 는Pytest의 가장 강력한 기능 중 하나로써, 테스트의 설정(setup)과 정리(cleanup)를 담당하는 특별한 함수입니다. 픽스처를 사용하면 여러 테스트 케이스에서 공통으로 사용할 수 있어, 코드의 재사용성을 크게 높여줍니다.

 

이전 글에서 작성한 Accumulator 클래스를 위한 테스트 코드(test_accum.py)에서는 Accumulator() 객체를 반복해서 만들어야 했던 문제가 있었습니다. 이는 DRY(Don't Repeat Yourself) 원칙에 위배됩니다.

 

<이전 글에서 작성했던 코드, accum=Accumulator() 코드가 반복 사용되고 있다.>

def test_accumulator_init():
    accum = Accumulator()    #코드가 반복됨
    assert accum.count == 0


def test_accumulator_add_one():
    accum = Accumulator()   #코드가 반복됨
    accum.add()
    assert accum.count == 1


def test_accumulator_add_three():
    accum = Accumulator()   #코드가 반복됨
    accum.add(3)
    assert accum.count == 3

 

그렇다고 Accumulator 객체를 만들지 않고 테스트할 수는 없기 때문에 좀 더 나은 구현 방법을 찾는 것이 필요합니다.

이런 문제는 Fixture 함수를 사용하여 해결할 수 있습니다.

 

Fixture 함수 사용 방법

@pytest.fixture
def accum():
  return Accumulator()
  
  def test_accumulator_init(accum):
  assert accum.count == 0

 

위와 같이 작성하면 pytest는 자동으로 테스트 함수의 매개변수에 있는 이름과 일치하는 accum Fixture를 호출하고, 해당 픽스처의 return 값을 테스트함수의 매개변수로 주입하게 되는 것입니다.

따라서 위 코드의 테스트 함수에서 accum 변수는, accum() 픽스처에 의해 생성된 객체를 참조하게 됩니다.

 

이렇게 작성하면 코드가 더 간결해져, 가독성이 좋고 유지보수가 쉬워집니다.

 

이전에 작성했던 나머지 테스트 함수들도 모두 픽스처로 리팩터링해보겠습니다.

def test_accumulator_init(accum):
  assert accum.count == 0

def test_accumulator_add_one(accum):
  accum.add()
  assert accum.count == 1

def test_accumulator_add_three(accum):
  accum.add(3)
  assert accum.count == 3

def test_accumulator_add_twice(accum):
  accum.add()
  accum.add()
  assert accum.count == 2

def test_accumulator_cannot_set_count_directly(accum):
  with pytest.raises(AttributeError, match=r"can't set attribute") as e:
    accum.count = 10

 

반복되는 코드만 줄였는데도, 코드가 간결해지고 테스트 결과도 동일하게 모두 패스임을 확인할 수 있었습니다.

 

pytest에서 제공하는 fixture 함수는테스트를 함수로 구조화하여  다른 클래스 구조를 가진 라이브러리들(Unittest 등)의 한계를 벗어날 수 있습니다.

클래스의 경우, 각 클래스는 자신만의 setup과 cleanup 방식을 가지면서 다른 클래스와 공유하지 않습니다. 실수로 A 클래스에서 B 클래스의 setup 코드를 사용 하려고하면 문제가 발생합니다.

하지만 픽스처는 모든 모듈의 모든 테스트 함수에서 공유할 수 있어, 의도하지않은 사이드 이펙트에서 벗어날 수 있습니다.

 

Fixture 함수의 다양한 기능

1. tests 폴더 안에 conftest.py 모듈을 만들고 그 안에 fixture들을 저장해 놓으면 Pytest가 자동으로 이 모듈에서 픽스처를 자동으로 가져와서 사용합니다. 

 

2. return 대신 yield 를 사용하면 테스트의 시작과 끝을 한번에 관리할 수 있습니다.

@pytest.fixture
def accum():
    # 이 부분이 준비 단계(Setup)
    test_object = Accumulator()
    
    # 테스트할 객체를 건네주고
    yield test_object
    
    # 테스트 끝나면 무조건 실행되는 정리 단계(Cleanup)
    print("테스트 완료!")

위와 같이 yield를 사용하면 테스트 환경을 초기화 하는 등 cleanup 단계를 잊지않고 진행할 수 있습니다.

 

3. 픽스처의 범위를 설정할수 있습니다.

- 기본값 : Funtion 범위 (테스트 함수가 실행될때마다 새로 생성)
   -> 각 테스트마다 새로운 객체가 필요하거나, 상태가 자주 변경되는 테스트에 사용

- session 범위 : 전체 테스트 과정에서 단 한번만 실행 / 대용량 파일을 한번만 읽어올때 유용함
   -> 큰 데이터 파일을 로딩하거나 데이터 베이스를 연결하는 등,  한번만 초기화해도 되는 테스트에 사용

- class / module / package : 각 단위로 한번만 실행

 

테스트의 독립성을 지키는 선에서 픽스처의 범위를 설정하는 것이 좋습니다.

 

추가로 pytest에서 제공하는 픽스처들도 한번 읽어봐주세요.

  • monkeypatch can be used for modifying classes, functions, and other objects
  • request provides test case metadata
  • tmpdir and tmp_path provide temporary directories

 


위 내용은 Test Automation University - Pytest 강의 내용을 정리하고, 추가로 이해한 내용을 작성한 게시물임을 참고 부탁드립니다.

 

 

Chapter 6 - Fixtures

 

testautomationu.applitools.com