javascript/이외
[jest] 동일 파일 내의 함수 mocking하기
blaxsior
2023. 8. 23. 00:15
- 코드 깃허브 주소: https://github.com/blaxsior/my_nest_study/tree/master/capp/src/auth/util
- 참고한 내용: https://stackoverflow.com/questions/45111198/how-to-mock-functions-in-the-same-module-using-jest
export async function genHash(user_pass: string, salt: string) {
return (await pbkdf2(user_pass, salt, 100000, 64, 'sha512')).toString('hex');
}
export async function generatePassword(user_pass: string) {
const salt = randomBytes(16).toString('hex'); // random salt 생성
const hash = await genHash(user_pass, salt); // 해시 생성
return `${hash}.${salt}`; // 해시 + salt 조합한 비밀번호 정보 반환
}
패스워드 기능을 구현하기 위해 위와 같이 코드를 작성했다. 이때 generatePassword를 테스트할 때 실제로 genHash가 호출되는지 알아보고 싶어 jest.spyOn 함수를 이용하여 mocking을 시도했다.
describe('func generatePassword', () => {
it('should call genHashFunction Once', async () => {
//Arange
const input = 'test';
const genHashSpyFn = jest
.spyOn(pwmodule, 'genHash')
.mockImplementation((user_pass, salt) => {
return new Promise((resolve) => {
resolve(Buffer.from(user_pass + salt).toString('hex'));
});
});
//Act
const result = await pwmodule.generatePassword(input);
console.log(result);
//Assertion
expect(genHashSpyFn).toHaveBeenCalled();
//Restore
genHashSpyFn.mockRestore();
});
나는 위 코드가 정상적으로 동작해야 한다고 생각했지만, 실제로는 다음과 같이 테스트에 실패했다.
찾아본 내용에 따르면 여러가지 방법이 존재했다.
- password 모듈 내에서 import * as thisModule './password'; 같은 문장을 추가, thisModule.~ 형태로 접근한다. es6의 cyclic import 지원을 통해 가능하다고 한다.
- 함수들을 클래스로 묶는다. ( 동작하기는 하는데, 실제 코드를 변경함 )
- 함수들을 의존성 주입 형태로 처리한다. ( 실제 코드를 변경하므로 나쁨 )
- babel을 사용하는 경우 babel-rewire-plugin 사용
- 함수 표현식으로 변경
1 ~ 3번 선택지의 경우 테스팅을 위해 실제 동작에 필요하지 않은 사항을 추가하거나, 구현을 일부 변경해야 하는 번거로움이 있어 선택하고 싶지 않았다. 1번의 경우 실제로는 동작했다. 4번은 babel을 사용하지 않는 환경에서는 적용할 수 없는 방법이라 선택하기 껄끄러웠다.
결과적으로 실제 함수 구현에 큰 영향을 주지 않는 5번을 선택했고, 실제로 동작했다.
export const genHash = async (user_pass: string, salt: string) => {
return (await pbkdf2(user_pass, salt, 100000, 64, 'sha512')).toString('hex');
};
export const generatePassword = async (user_pass: string) => {
const salt = randomBytes(16).toString('hex'); // random salt 생성
const hash = await genHash(user_pass, salt); // 해시 생성
return `${hash}.${salt}`; // 해시 + salt 조합한 비밀번호 정보 반환
};
이외로 테스트해본 결과, 현재 mocking 대상이 되는 genHash가 함수 표현식(혹은 화살표 함수) 형태로 나타나야만 mocking이 제대로 동작했다.
명확한 이유에 대해서는 잘 모르겠지만, jest의 mock 동작 방식에 해답이 있지 않을까 싶다. jest를 이용하여 다른 모듈에 있는 함수를 mocking하는 경우에는 함수 선언문으로 작성되어 있더라도 별 문제가 없었기 때문에 더 요상한 문제다...