factory-boy와 Faker로 실제 같은 테스트 데이터 대량 생성하기
테스트 코드의 품질과 생산성을 극적으로 높이는 factory-boy와 Faker 라이브러리로 실제 데이터와 유사한 '살아있는' 테스트 데이터를 대량으로 효율적으로 생성하는 방법
테스트 데이터 생성의 문제점
유지보수 어려움: 모델 필드 변경 시 모든 테스트 코드 수정 필요
다양성 부족: 단순한 고정 데이터로는 현실적인 엣지 케이스 커버 불가
가독성 저하: 데이터 생성 코드가 테스트 핵심 로직을 방해
기본 설정 및 Factory 정의
pip install factory-boy FakerUserFactory 예시
import factory
from faker import Faker
from django.contrib.auth import get_user_model
fake = Faker('ko_KR')
class UserFactory(factory.django.DjangoModelFactory):
class Meta:
model = get_user_model()
django_get_or_create = ('username',)
first_name = factory.Faker('first_name', locale='ko_KR')
last_name = factory.Faker('last_name', locale='ko_KR')
username = factory.LazyAttribute(lambda o: f'{o.first_name}{o.last_name}_{fake.lexify("????")}')
email = factory.Faker('email')
password = factory.PostGenerationMethodCall('set_password', 'defaultpassword123')핵심 Factory 기능
SubFactory vs LazyAttribute
SubFactory: 관계된 객체를 실제로 DB에 생성하여 연결
LazyAttribute: 자신의 다른 속성값을 참조하여 동적으로 값 생성
Sequence로 유니크 필드 처리
name = factory.Sequence(lambda n: f'item-{n}')post_generation으로 M2M 필드 처리
@factory.post_generation
def tags(self, create, extracted, **kwargs):
if not create:
return
if extracted:
for tag_name in extracted:
tag, _ = Tag.objects.get_or_create(name=tag_name)
self.tags.add(tag)Trait로 팩토리 변형
class Params:
is_sold_out = factory.Trait(
status=Product.Status.SOLD_OUT,
stock=0
)테스트 코드에서 Factory 활용
class ProductAPITestCase(APITestCase):
def setUp(self):
self.user = UserFactory()
self.products = ProductFactory.create_batch(5, owner=self.user)
self.client.force_authenticate(user=self.user)
def test_list_products(self):
url = "/api/products/"
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 5)실무 팁
create vs build 전략
create(): DB에 실제 레코드 저장, 객체 생성 후 DB 조회 필요한 테스트용
build(): 파이썬 객체만 생성, API request body 생성용으로 속도 빠름
재현 가능한 테스트
from faker import Faker
Faker.seed(0) # 동일한 데이터셋으로 테스트 실행Factory 파일 관리
각 앱 디렉토리에
factories.py파일로 관리공용 Factory는
core나common앱에 모아서 관리
Last updated
