테스트 종류
테스트 종류
Unit Test
함수나 클래스처럼 가장 작은 단위의 로직을 독립적으로 테스트
데이터를 Mocking 하여 Test(서비스 로직 + Mocking Data)
Integration Test
목적 : 데이터베이스 연동이 올바르게 동작하는지 확인
데이터베이스 등 다양한 요소와 함께 실행을 하여 테스트
Test DB를 사용하여 Test(서비스 로직 + DB)
E2E Test(End To End)
목적 : API 엔드포인트가 클라이언트 입장에서 정상적으로 동작하는지 확인
클라이언트 측면에서 애플리케이션이 정상적으로 동작하는지 테스트
API를 호출하여 Test(Controller+API)
E2E 테스트에서 API를 테스트하는데, 굳이 Integration Test를 해야 하나?
Integration Test와 E2E Test는 목표와 범위가 다르기 때문에, 둘 다 의미가 있습니다.
위에서 봤듯이, E2E는 API 호출하여 HTTP 요청 → 컨트롤러 → 서비스 → DB → 응답 전체적인 흐름을 테스트합니다. Integration Test는 서비스 → DB까지만 테스트하죠.
E2E는 API 호출하는 것이기때문에 서비스 로직의 상세한 로직까지 테스트하지 못합니다. 물론 Unit Test에서 service의 상세한 로직을 테스트하긴 하지만 이는 Mocking Data니까요.
때문에 E2E에서 부족한 서비스의 상세한 로직 테스트와 더불어 Unit Test에서의 Mocking Data라는 점을 보완해줄 실제 DB라는 관점에서 필요한 것이 Integration Test입니다.
그리하여 테스트를 조금 더 견고하게 하기 위해서는 Integration Test를 하는 것도 좋습니다.
각 테스트별 예제
그렇다면 설명보다는 이해하기 더 쉽도록 예제로 알아보도록 하겠습니다.
Integration Test
통합 테스트는 각 서비스(UseCase) 파일별로 integration 파일도 쌍에 맞게 생성하여 테스트할 것입니다.
그리고 Integration Test는 실제 DB를 사용한다고 하였는데 sqlite라는 DB를 사용할 것입니다.
sqlite는 데이터가 디스크 파일로 저장됩니다.
그렇다면 예제 코드를 살펴보겠습니다.
우선 셋팅코드입니다.
tech 도메인(개발 기술 관리해주는 도메인)에 대한 코드를 예제로 하겠습니다.
app.module에서 셋팅하는 것처럼 TypeORM DB setting과 사용할 Entity들을 셋팅해줍니다.
그리고 주입할 서비스들을 주입해줍니다.
모듈 셋팅
import { Test, TestingModule } from "@nestjs/testing";
import { TypeOrmModule } from "@nestjs/typeorm";
import { TransactionModule } from "../../../../../shared/transaction/transaction.module";
import { User } from "../../../../user/entities/user.entity";
import { Tech } from "../../../adapter/output/typeorm/entities/tech.entity";
import { ManageTechRepositoryOutputAdapter } from "../../../adapter/output/typeorm/repository/manage-tech.repository.output.adapter";
import { UpdateTechRepositoryOutputAdapter } from "../../../adapter/output/typeorm/repository/update-tech.repository.output.adapter";
import { ManageTechUseCase } from "../../manage-tech.use-case";
import { UpdateTechUseCase } from "../../update-tech-use-case";
describe("Update () Integration Test", () => {
beforeAll(async () => {
const module: TestingModule =
await Test.createTestingModule({
imports: [
TypeOrmModule.forRoot({
type: "sqlite",
database: ":memory:",
dropSchema: true,
entities: [Tech, User],
synchronize: true,
}),
TypeOrmModule.forFeature([Tech]),
TransactionModule,
],
providers: [
ManageTechUseCase,
{
provide: "ManageTechRepositoryOutputPort",
useClass: ManageTechRepositoryOutputAdapter,
},
UpdateTechUseCase,
{
provide: "UpdateTechRepositoryOutputPort",
useClass: UpdateTechRepositoryOutputAdapter,
},
],
}).compile();
});
});