-
Notifications
You must be signed in to change notification settings - Fork 0
mongodb memory server 를 이용한 단위 테스트 시 mongoDB 의존성 제거
Min-h-96 edited this page Nov 28, 2022
·
4 revisions
Service 계층의 로직들이 정상적으로 동작하는지 테스트 하기 위해서는 DB 에 접근을 해야할 때가 있습니다.
하지만, 테스트를 위해 실제 사용하고 있는 DB 에 접근하는 것은 말도 안됩니다. 현재 배포되고 있는 서비스라면 테스트를 하다가 어떤 문제가 발생할 수 도 있으니까요.
mongodb-memory-server 패키지를 사용하면, 실제 DB 에 접근하지는 않지만 구현된 Repository 계층의 로직과 함께 MongoDB 를 이용할 수 있습니다.
mongodb-memory-server 패키지는 테스트용 MongoDB 서버를 키는 패키지입니다. 예시와 함께 어떻게 활용할 수 있는지 살펴보겠습니다.
// user.service.spec.ts
describe('UserService', () => {
let userService: UserService;
let userRepository: UserRepository;
let mongod: MongoMemoryServer;
let mongoConnection: Connection;
let userModel: Model<User>;
beforeAll(async () => {
mongod = await MongoMemoryServer.create();
const uri = mongod.getUri();
mongoConnection = (await connect(uri)).connection;
userModel = mongoConnection.model(User.name, userSchema);
const module: TestingModule = await Test.createTestingModule({
providers: [
UserService,
UserRepository,
{
provide: getModelToken(User.name),
useValue: userModel,
},
],
}).compile();
userService = module.get<UserService>(UserService);
userRepository = module.get<UserRepository>(UserRepository);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
위 처럼 코드를 작성해서 테스트용 MongoDB 서버를 사용할 수 있습니다.
차례대로 설명을 드리면,
-
MongoMemoryServer.create()
는 테스트용 MongoDB 서버를 만들고, 데몬을 가져옵니다. -
getUri()
를 이용하여 MongoDB 에 접근하기 위한 uri 를 가져옵니다. - uri 를 이용하여 MongoDB 에 연결하고, 그 연결을
mongoConnection
이라는 값으로 가져옵니다. -
mongoConnection
을 통해서, 우리가 조작하고자 하는 모델을 얻습니다. - 마지막으로
getModelToken()
을 이용하여, 모델을 주입합니다.
이 다음으로 beforeAll
을 이용하여 테스트용 MongoDB 서버를 실행시켰으니, 모든 테스트가 끝난 이후에 실행시킨 MongoDB 서버를 종료시키는 로직이 필요합니다. 이 로직은 afterAll
과 afterEach
안에 나눠서 작성됩니다.
// user.service.spec.ts
describe('UserService', () => {
// ... 중략 ...
afterAll(async () => {
await mongoConnection.dropDatabase();
await mongoConnection.close();
await mongod.stop();
}
afterEach(async () => {
const collections = mongoConnection.collections;
for (const key in collections) {
const collection = collections[key];
await collection.deleteMany({});
}
});
};
-
afterAll
블록에서 모든 데이터베이스를 삭제하고, 연결을 종료하고, 데몬을 중지하는 코드입니다. -
afterEach
에서는 각각의 개별 테스트 후에, 컬렉션에 생성된 모든 항목(document)을 삭제하는 구문입니다. 실제 사용된 컬렉션을 User 하나이지만, 더 일반적으로 동작할 수 있게끔 코드가 짜여져있습니다.
이제 테스트를 위한 기본 설정이 끝이 났습니다. 이를 이용하여 테스트를 진행해보겠습니다.
it('테스트', async () => {
const userData = {
authProvider: 'google',
authId: '53361445',
email: '[email protected]',
username: 'minchoi',
};
const user = await userRepository.create(userData);
const foundUser = await userService.findOne(
userData.authProvider,
userData.authId,
);
expect(foundUser._id).toEqual(user._id);
});
테스트는 실제 프로덕트 코드에서 User 를 생성하기 위해 필요한 데이터로 직접 userRepository.create()
를 이용해서 User 를 생성하고, 잘 생성됐는지 userService.findOne()
함수로 찾은 User 와 동일한 지를 확인하는 테스트 입니다.
- 📃 기획서
- 📂 Backlog
- 📊 ERD, 폴더 구조
- 🗓️ 회의록