Pytest fixture로 테스트 데이터 관리하기: 야근 줄이는 법
- 08 Dec, 2025
Pytest fixture로 테스트 데이터 관리하기: 야근 줄이는 법
야근의 시작
금요일 오후 6시. 퇴근 30분 전이다.
“J님, 테스트 스위트 돌리는 데 왜 이렇게 오래 걸려요?”
개발팀장 질문이다. 답은 알고 있다. 매번 디비 초기화하느라 30분씩 날린다.
“최적화 좀 해보겠습니다.”
그렇게 주말을 픽스처 공부로 보냈다.

문제는 반복이었다
월요일 출근. 테스트 코드를 다시 봤다.
def test_user_login():
db = create_db_connection()
db.clean_all_tables()
db.insert_test_user()
# 실제 테스트
result = login("test@test.com")
assert result.success
db.close()
def test_user_logout():
db = create_db_connection()
db.clean_all_tables()
db.insert_test_user()
# 실제 테스트
result = logout()
assert result.success
db.close()
똑같은 셋업이 50개 테스트마다 반복된다. 디비 초기화가 30초씩 걸린다.
50개 × 30초 = 25분. 순수 셋업 시간만.
“이거 미친 짓이었네.”
픽스처 공부한 보람이 있다. 바로 리팩토링 시작했다.
fixture 기본부터
conftest.py 파일을 만들었다.
import pytest
@pytest.fixture
def db_connection():
db = create_db_connection()
yield db
db.close()
yield가 핵심이다. 앞은 셋업, 뒤는 티어다운. 자동으로 실행된다.
테스트 코드가 간단해졌다.
def test_user_login(db_connection):
db = db_connection
result = login("test@test.com")
assert result.success
close()를 신경 쓸 필요가 없다. 픽스처가 알아서 정리한다.
첫 번째 개선. 5분 절약.

scope로 시간 줄이기
문제는 여전했다. 매 테스트마다 디비 연결을 새로 만든다.
scope를 알게 됐다.
@pytest.fixture(scope="session")
def db_connection():
db = create_db_connection()
yield db
db.close()
session scope. 전체 테스트 스위트에서 한 번만 실행된다.
하지만 문제가 생겼다. 테스트끼리 데이터가 꼬인다.
“아, 연결은 유지하되 데이터는 초기화해야 하는구나.”
다시 수정했다.
@pytest.fixture(scope="session")
def db_connection():
db = create_db_connection()
yield db
db.close()
@pytest.fixture(scope="function")
def clean_db(db_connection):
db_connection.clean_all_tables()
return db_connection
연결은 세션당 한 번. 테이블 초기화는 테스트마다.
실행 시간이 25분에서 8분으로 줄었다. 17분 절약.
“이제 좀 사람 사는 거 같네.”
테스트 데이터 픽스처
다음 문제. 테스트 데이터 준비가 중복됐다.
def test_admin_access(clean_db):
admin = User(email="admin@test.com", role="admin")
clean_db.insert(admin)
result = access_admin_page(admin)
assert result.success
def test_admin_delete(clean_db):
admin = User(email="admin@test.com", role="admin")
clean_db.insert(admin)
result = delete_user(admin)
assert result.success
admin 유저 생성 코드가 계속 반복된다.
픽스처로 뺐다.
@pytest.fixture
def admin_user(clean_db):
admin = User(email="admin@test.com", role="admin")
clean_db.insert(admin)
return admin
def test_admin_access(admin_user):
result = access_admin_page(admin_user)
assert result.success
테스트 코드가 의도만 남았다. 셋업 코드가 사라졌다.
가독성이 올라갔다. 유지보수도 쉬워졌다.
파라미터로 여러 케이스
일반 유저, 관리자, 게스트. 세 가지 권한 테스트가 필요했다.
처음엔 테스트를 세 개 만들려고 했다. 비효율적이다.
@pytest.fixture(params=[
{"email": "user@test.com", "role": "user"},
{"email": "admin@test.com", "role": "admin"},
{"email": "guest@test.com", "role": "guest"}
])
def test_user(request, clean_db):
user = User(**request.param)
clean_db.insert(user)
return user
def test_user_access(test_user):
result = access_page(test_user)
assert result.success
테스트 하나가 자동으로 세 번 실행된다. 각각 다른 유저로.
pytest 출력도 깔끔하다.
test_user_access[user] PASSED
test_user_access[admin] PASSED
test_user_access[guest] PASSED
코드는 한 번 작성. 케이스는 무한 확장.

autouse로 자동 실행
로그 관리가 필요했다. 모든 테스트마다.
@pytest.fixture(autouse=True)
def setup_logging():
logger = setup_test_logger()
yield
logger.save_results()
autouse=True. 명시 안 해도 자동으로 실행된다.
모든 테스트 함수에 로깅이 적용됐다. 코드 수정 없이.
“이건 진짜 마법 같네.”
실전 구조
conftest.py를 계층화했다.
tests/
conftest.py # 전역 픽스처
api/
conftest.py # API 테스트용
test_user.py
ui/
conftest.py # UI 테스트용
test_login.py
전역 conftest.py:
@pytest.fixture(scope="session")
def db_connection():
# 디비 연결
pass
@pytest.fixture
def clean_db(db_connection):
# 테이블 초기화
pass
api/conftest.py:
@pytest.fixture
def api_client():
# API 클라이언트
pass
@pytest.fixture
def auth_header(api_client):
# 인증 헤더
pass
필요한 픽스처만 불러온다. 테스트가 가벼워졌다.
픽스처 조합
픽스처끼리 조합할 수 있다.
@pytest.fixture
def user(clean_db):
user = User(email="test@test.com")
clean_db.insert(user)
return user
@pytest.fixture
def logged_in_user(user, api_client):
token = api_client.login(user)
user.token = token
return user
@pytest.fixture
def user_with_data(logged_in_user, clean_db):
data = create_test_data()
clean_db.insert_for_user(logged_in_user, data)
return logged_in_user
세 단계 픽스처다. 로그인까지, 데이터까지. 선택 가능하다.
def test_simple(user):
# 유저만 필요
pass
def test_with_login(logged_in_user):
# 로그인된 유저
pass
def test_full_scenario(user_with_data):
# 전부 준비된 상태
pass
필요한 만큼만 셋업한다. 시간 절약이다.
실제 성과
리팩토링 전후 비교했다.
전:
- 테스트 50개 실행: 32분
- 셋업 코드 중복: 200줄
- 디비 연결: 50번
- 티어다운 누락: 가끔
후:
- 테스트 50개 실행: 8분
- 픽스처 재사용: 10개
- 디비 연결: 1번
- 티어다운: 자동
24분 절약. 하루에 테스트 3번 돌린다. 72분 단축.
주 5일이면 6시간. 거의 야근 하루가 사라졌다.
팀원 반응
후배 QA한테 픽스처 가르쳤다.
“이거 진짜 편하네요.”
개발팀장도 만족했다.
“CI 파이프라인이 30분 빨라졌어요.”
테크 리드가 물었다.
“다른 팀도 적용 가능할까요?”
“conftest.py 공유하면 됩니다.”
지금은 전사 표준이 됐다. 모든 테스트가 픽스처 기반이다.
주의할 점
픽스처 남용하지 말 것.
간단한 테스트에 복잡한 픽스처는 과하다. 테스트 3줄인데 픽스처 20줄이면 문제다.
scope 실수 조심. session scope에 function 데이터 넣으면 망한다.
픽스처 이름 명확하게. data보다 user_test_data가 낫다.
의존성 순환 주의. 픽스처가 서로 부르면 안 된다.
다음 단계
factory_boy 도입 검토 중이다. 픽스처 + 팩토리 패턴.
@pytest.fixture
def user_factory(clean_db):
return UserFactory
def test_multiple_users(user_factory):
users = user_factory.create_batch(10)
# 10명 유저로 테스트
더 유연해진다. 랜덤 데이터도 가능하다.
Faker 라이브러리도 붙이면 좋겠다. 실제 같은 데이터로.
지금 시작하기
픽스처 리팩토링 순서:
- 중복 셋업 코드 찾기 (Ctrl+F “setup”)
- conftest.py 만들고 기본 픽스처 작성
- yield로 티어다운 자동화
- scope 최적화 (function → class → module → session)
- 파라미터로 케이스 확장
- 팀 공유
하루면 충분하다. 효과는 즉시 나타난다.
마무리
금요일 6시. 테스트 스위트 실행했다.
8분 만에 완료. 초록불.
“퇴근 가능.”
야근이 사라졌다. 픽스처 덕분이다.
테스트 코드도 코드다. 리팩토링이 필요하다. 반복을 제거하고 재사용하라.
시간은 돌아온다. 야근 대신 정시 퇴근으로.
이제 pytest.ini 설정도 정리해야겠다. 커버리지 리포트 경로가 엉망이다.
