테스트 주도 개발(Test-Driven Development, TDD)은 소프트웨어 개발 방법론 중 하나로, 테스트 코드를 먼저 작성한 후에 해당 테스트를 통과하는 코드를 작성하는 방식입니다. 이것은 소프트웨어의 품질 향상과 유지보수의 용이성을 높여주는 장점을 가지고 있습니다. 자바스크립트에서도 TDD를 적용하여 품질 좋은 코드를 작성할 수 있습니다.
TDD에서 중요한 요소 중 하나는 테스트 더블(Test Double)입니다. 테스트 더블은 실제 의존성을 가진 객체를 대체하여 테스트에서 사용되는 가짜 객체입니다. 테스트 더블은 다음과 같은 목적으로 사용될 수 있습니다.
스텁(Stub)
스텁은 테스트 더블의 일종으로, 특정 메서드의 반환값이나 동작을 가짜로 대체하여 테스트가 정상적으로 진행될 수 있게 합니다. 예를 들어, 외부 API를 호출하는 코드의 테스트를 작성할 때, 실제 API를 호출하지 않고 스텁을 주입하여 특정 값을 반환하게 할 수 있습니다.
class ExternalAPI {
fetchData() {
// 실제로는 외부 API를 호출하여 데이터를 가져옴
}
}
class MyClass {
constructor(externalAPI) {
this.externalAPI = externalAPI;
}
getDataFromExternalAPI() {
const data = this.externalAPI.fetchData();
// 데이터 처리 로직
return processedData;
}
}
// 테스트 코드
const stubAPI = {
fetchData: () => {
return fakeData; // 가짜 데이터 반환
}
};
const myClass = new MyClass(stubAPI);
const result = myClass.getDataFromExternalAPI();
// result와 예상 결과 비교
모의 객체(Mock)
모의 객체는 실제 객체와 유사한 동작을 가지면서도, 호출 여부나 전달된 인자를 검증할 수 있는 테스트 더블입니다. 예를 들어, 메일을 전송하는 클래스의 테스트를 작성할 때, 모의 객체를 사용하여 메일 전송 메서드가 제대로 호출되는지를 검증할 수 있습니다.
class EmailSender {
sendEmail(to, subject, body) {
// 이메일 전송 로직
}
}
class MyMailer {
constructor(emailSender) {
this.emailSender = emailSender;
}
sendWelcomeEmail(user) {
this.emailSender.sendEmail(user.email, 'Welcome', 'Hello!');
}
}
// 테스트 코드
const mockEmailSender = {
sendEmail: jest.fn() // 모의 메서드로 대체
};
const myMailer = new MyMailer(mockEmailSender);
myMailer.sendWelcomeEmail({ email: 'test@example.com' });
expect(mockEmailSender.sendEmail).toHaveBeenCalledWith('test@example.com', 'Welcome', 'Hello!');
스파이(Spy)
스파이는 실제 객체와 유사한 동작을 가지면서, 호출된 횟수나 호출된 인자 값을 기록하고 검증할 수 있는 테스트 더블입니다. 스파이는 메서드가 호출되었는지, 얼마나 자주 호출되었는지 등을 확인하고 테스트의 일부로 활용할 수 있습니다.
class MathUtils {
sum(a, b) {
return a + b;
}
}
// 테스트 코드
const mathUtils = new MathUtils();
const sumSpy = jest.spyOn(mathUtils, 'sum');
const result = mathUtils.sum(2, 3);
expect(sumSpy).toHaveBeenCalled();
expect(sumSpy).toHaveBeenCalledWith(2, 3);
expect(result).toBe(5);
테스트 더블을 활용하여 자바스크립트 TDD를 수행하면, 의존성이 있는 코드의 테스트를 더 쉽고 견고하게 작성할 수 있습니다. 이로써 코드의 품질을 향상시키고 유지보수를 용이하게 할 수 있습니다.
참고 자료: