목차
Test Fixture 란
소프트웨어 테스트에서 테스트 환경을 설정하고 관리하기 위한 코드 집합을 의미합니다. 테스트가 정확하고 일관성 있게 실행될 수 있도록 준비하는 과정입니다. 이는 테스트를 위해 필요한 모든 상태나 환경을 포함합니다. 예를 들어, 데이터베이스를 설정하거나, 필요한 객체를 생성하거나, 특정 상태로 초기화하는 작업이 포함됩니다.
Test Fixture를 구성하는 기본 원칙
- 독립적인 테스트 환경 구성: 이전 테스트의 실행이 이후 테스트에 영향을 주지 않도록 하기 위해, beforeEach 또는 afterEach를 사용해 환경을 초기화하고 정리
- Setup과 Teardown 구분
- SetUp : beforeAll, beforeEach 메서드를 사용하여 필요한 초기 설정
- Teardown : afterAll, afterEach를 사용해 자원을 정리
- 재사용 가능한 코드 작성: 공통된 설정이나 데이터 준비 작업을 별도의 헬퍼 함수나 클래스로 추출하여, 필요할 때 재사용할 수 있게 작성
Test Fixture를 사용하는 이유
- 테스트가 항상 동일한 조건에서 실행되며, 테스트의 독립성과 신뢰성을 보장
- 사용하면 코드가 간결해지고, 유지보수성이 높아지며, 자동화된 테스트 실행이 용이
예제 상황
- 데이터베이스 테스트: 데이터베이스를 사용하는 애플리케이션의 경우, 각 테스트 전에 데이터베이스를 특정 상태로 초기화하고, 테스트 후에 정리하는 작업을 Test Fixture로 구성
- HTTP 요청 테스트: API 테스트에서는 각 요청에 대한 환경 설정(예: 모의 데이터 또는 인증 토큰 설정)을 Test Fixture로 구성
NestJS에서의 Test Fixture
NestJS에서 테스트를 작성할 때, beforeEach, afterEach, beforeAll, afterAll을 사용하여 테스트 픽스처를 구성할 수 있습니다. 주로 TestingModule을 사용하여 애플리케이션 모듈의 인스턴스를 생성하고, 의존성을 주입하는 작업이 포함
구성 요소 설명
- TestingModule: NestJS의 테스트 모듈을 생성하여 의존성을 주입하고, 각 컴포넌트가 올바르게 동작하는지 확인합니다.
- beforeAll: 테스트 스위트 내에서 한 번만 실행되는 초기화 코드입니다. 여기서 TestingModule을 컴파일하고 컨트롤러와 서비스를 인스턴스화합니다.
- beforeEach: 각 테스트가 실행되기 전에 실행되어, 테스트 상태를 초기화하거나 Jest의 mock을 재설정합니다.
- afterAll: 테스트가 모두 종료된 후 한 번 실행되어, 테스트 환경을 정리하거나 자원을 해제합니다.
NestJS와 Jest를 사용하여 테스트 픽스처를 구성하는 방법을 보여주는 예제
import { Test, TestingModule } from '@nestjs/testing';
import { MyService } from './my.service';
import { MyController } from './my.controller';
describe('MyController', () => {
let controller: MyController;
let service: MyService;
beforeAll(async () => {
// 모든 테스트 전에 실행되는 setup 작업 (한 번만 실행)
const module: TestingModule = await Test.createTestingModule({
controllers: [MyController],
providers: [MyService],
}).compile();
controller = module.get<MyController>(MyController);
service = module.get<MyService>(MyService);
});
beforeEach(() => {
// 각 테스트 전에 필요한 초기화 작업 수행
jest.clearAllMocks(); // Jest의 모든 mock 초기화
});
afterEach(() => {
// 각 테스트 후 자원 해제나 초기화 작업
});
// 테스트
it('should return expected data', async () => {
const result = 'expected result';
jest.spyOn(service, 'getData').mockImplementation(() => result);
expect(await controller.getData()).toBe(result);
});
afterAll(() => {
// 모든 테스트 후에 실행되는 teardown 작업 (한 번만 실행)
// 테스트 모듈 정리 또는 자원 해제
});
});
반복되는 코드를 모두 Fixture를 만들어서 해야 할까?
경우에 따라 다르겠지만, 테스트 상황에서 기본적으로 몰라도 되는 확인해보지 않아도 되는 코드는 Fixture를 생성해서 구현하는 것이 좋아 보인다. 예를 들어, 데이터 베이스 초기화같은 것이 있겠다.
하지만, 유저 생성, 토큰생성 등을 beforeAll 이나 beforeEach 에 구현해 버리면 각 테스트 마다 확인하기 위해 코드의 위 아래를 오가야하므로 오히려 비효율적이라고 생각한다.
차라리, 해당 기능들을 함수나 클래스를 만들어서 각 테스트에서 호출하여 사용하는 방법이 해당 테스트를 더 빨리 이해할 수 있을 것 같다.
'TDD > 개념' 카테고리의 다른 글
[ TDD ] 런던파 vs 고전파 (0) | 2024.12.02 |
---|