개발자는 요구사항을 검증하는 자동화된 테스트 케이스를 작성한다. 그런 후, 그 테스트 케이스를 통과하기 위한 최소한의 코드를 생성한다.
마지막으로 작성한 코드를 표준에 맞도록 리팩토링한다.
🔥 문제를 작은 단위로 정의하고, 피드백을 자주 받으면서 그 해답을 찾아가는 과정
기능 명세서 → 테스트코드 작성 → 코드 작성 → 리팩토링
javascript → 테스트 도구 (Jest)
조건 : 자동차
// 테스트 코드
describe("자동차 경주 테스트", () => {
test("자동차는 5자 이하의 이름을 가질 수 있다", async () => {
const name = "프론트엔드";
const car = new Car(name);
expect(car.name).toBe(name);
});
test("자동차는 6자 이상의 이름을 가질 수 없다", async () => {
const name = "자바스크립트";
expect(()=>{
new Car(name);
}).toThrow();
});
})
//car 클래스
class Car{
name;
constructor(name){
this.name = name;
if(name.length >= 6){
throw new Error("이름은 6자 이상 입력")
}
}
}
단위 테스트가 어려운 경우 (클래스 내부를 직접 컨트롤 못하는 경우)
조건 : 자동차 전진
// 테스트 코드
describe("자동차 경주 테스트", () => {
test("자동차는 0-9사이의 무작위 값을 구하고 4이상일 경우 전진", async () => {
const car = new Car("자동차");
car.move();
expect(car.position).toBe(1);
});
test("자동차는 0-9사이의 무작위 값을 구하고 4이하일 경우 전진x", async () => {
const car = new Car("자동차");
car.move();
expect(car.position).toBe(0);
});
});
//car 클래스
class Car{
name;
position = 0;
constructor(name){
this.name = name;
if(name.length >= 6){
throw new Error("이름은 6자 이상 입력")
}
}
move(){
const randomValue = Math.floor(Math.random() * 10);
if(randomValue >= 4){
this.position +=1;
}
}
}
⇒ 이렇게 될 경우, randomValue 값을 직접 컨트롤 할 수 없어, 단위테스트가 어렵다! (테스트 코드가 될 때도 있고, 안될 때도 있다.)
해결책 → 이럴 땐 랜덤 값을 상위로 보내고, move 메소드의 파라미터로 넘기고, move 메소드만 단위테스트를 가능하게끔 만든다.
// 테스트 코드
describe("자동차 경주 테스트", () => {
test("자동차는 0-9사이의 무작위 값을 구하고 4이상일 경우 전진", async () => {
const car = new Car("자동차");
car.move(4);
expect(car.position).toBe(1);
});
test("자동차는 0-9사이의 무작위 값을 구하고 4이하일 경우 전진x", async () => {
const car = new Car("자동차");
car.move(1);
expect(car.position).toBe(0);
});
});
//car 클래스
class Car{
name;
position = 0;
constructor(name){
this.name = name;
if(name.length >= 6){
throw new Error("이름은 6자 이상 입력")
}
}
move(randomValue){
if(randomValue >= 4){
this.position +=1;
}
}
}
→ 이렇게하면 테스트가 통과하게 된다.
test.each([0,1,2,3])("자동차는 %s일 경우 전진하지 않는다.",(condition)=>{
const car = new Car("자동차");
car.move(condition);
expect(car.position).toBe(0);
})