TDD 위해서는 Mock Test, Mock Function 이란 개념을 알고있어야만 합니다.
오늘은 Jest 에서 제공하는 Mock Function 을 통해 Mock Test 를 알아보겠습니다.
제일 먼저, Mock 이 무엇인가?
Mock 혹은 Mocking이란 의미 그대로 모조품 즉, 가짜객체를 의미합니다.
주로 “단위” 테스트를 작성할 때 해당 코드가 의존하고 있는 부분을 가짜로 대체하는 것을 말합니다.
왜 사용하지?
- 의존성 분리
- 테스트 격리성 유지
위 두가지 를 위해 Mocking을 합니다.
좀 더 자세히 설명하면, 가짜 객체를 사용해 단일 모듈 또는 클래스를 테스트 할 수 있도록 돕는데, A 클래스 에서 사용하는 B 클래스의 메서드를 Mocking 함을로써 B 클래스에 대한 의존성을 분리할 수 있습니다.
또한 실제 외부 리소스(DB 등) 나 서비스 등을 호출하지 않고 가짜 객체로 대체함으로써 테스트를 격리시켜 외부 요소의 변동으로 인한 테스트의 불안정성을 방지하려고 사용합니다.
jest.fn()
Jest 에서는 Mock Function 을 생성할떄 jest.fn()을 사용합니다.
.spyOn(), .mock() 등이 있지만 이번에는 jest.fn()만을 사용해서 Test를 진행하겠습니다.
// 공식문서 참고
const mockFn = jest.fn();
mockFn();
expect(mockFn).toHaveBeenCalled();
공식문서에는 위와 같이 사용하면 된다고 나와있습니다. 이해가 되지 않으니 직접 사용해보면서 더 알아보도록 하겠습니다.
구현
//product.test.js
//productModel은 mongoose model
describe('Product Controlller Create', () => {
let controller, req, res, next;
beforeEach(() => {
controller = new ProductController();
productModel.create = jest.fn();
req = httpMocks.createRequest();
res = httpMocks.createResponse();
next = jest.fn();
});
...
/**
1. 모킹한 함수에 .mockReturnValue() 로 newProd 라는 객체를 반환할 수 있도록 한다.
2. controller.createProduct를 호출한다.
3. 응답 객체의(res) JsonData가 newProd와 같은지 테스트
*/
it('should return json body in response', async () => {
productModel.create.mockReturnValue(newProd);
await controller.createProduct(req, res, next);
expect(res._getJSONData()).toStrictEqual(newProd);
})
/**
1. 모킹한 함수에 .mockReturnValue() 로 rejectedPromise 라는 비동기 에러를 반환할 수 있도록 한다.
2. controller.createProduct를 호출한다.
3. errorMessage 가 같이 호출되는지 테스트 한다.
*/
it('should handle errors', async () => {
const errorMessage = {message: "description property missing"};
const rejectedPromise = Promise.reject(errorMessage);
productModel.create.mockReturnValue(rejectedPromise);
await controller.createProduct(req, res, next);
expect(next).toBeCalledWith(errorMessage);
})
})
테스트하려는 기능이 제품 생성(createProduct) 이기 때문에 productModel 의 create function 을 모킹합니다. .create() 가 DB 에 접근하여 데이터를 조작하기 때문에 의존성 분리를 위해 모킹합니다.
같은 방법으로 next()도 모킹 합니다. 이는 에러 발생 시 에러를 트래킹 하기 위함입니다.
작성한 테스트 코드를 실행하면 에러가 납니다. 이유는 아직 createProduct는 newProd를 리턴해주지도 않고 예외처리도 되어있지 않기 때문입니다. 따라서 아래와 같이 테스트를 통과 가능하도록 코드를 작성해줍니다.
export class ProductController {
createProduct = async (req, res, next) => {
try {
const createdProduct = await productModel.create(req.body);
res.status(200).json(createdProduct);
} catch (error) {
next(error);
}
}
}
코드를 작성 후 테스트를 통과하는지 확인합니다.
'TDD' 카테고리의 다른 글
Jest - intelliJ[Window] 설정하기 (0) | 2024.03.20 |
---|---|
TDD 해보기 (1) (express, jest) (1) | 2024.02.06 |
Jest 란 (0) | 2024.02.05 |
TDD 란 (0) | 2024.02.05 |