Home TDD(3장) 정리
Post
Cancel

TDD(3장) 정리

테스트 코드 작성 순서

  • 쉬운 경우에서 어려운 경우로 진행
  • 예외적인 경우에서 정상인 경우로 진행

초반에 복잡한 테스트부터 시작하면 안 되는 이유

  • 초반부터 다양한 조합을 검사하는 복잡한 로직을 작성하면 해당 테스트를 통과하기 위해 한 번에 구현해야 할 코드가 많아진다.
    • 테스트를 통과시키기 위해 복잡한 규칙을 구현해야 함⇒ 막막해진다.
    • 한 번에 완벽한 코드를 만들면 좋겠지만, 모두가 슈퍼 개발자가 아니다.
      • 오히려 한 번에 많은 코드를 만들다 보면 버그를 더 많이 만들게 되고, 버그를 잡느라 시간을 허비하게됨

구현하기 쉬운 테스트부터 시작하기

  • 구현이 가장 쉬운 경우부터 시작하면 빠르게 테스트 통과 가능
    • 2장의 암호 강도 측정 예를 들면 모든 조건을 충족하는 경우
      • 단순히 STRONG을 반환하기만 하면 됨
    • 모든 조건을 충족하지 않는 경우를 들 수 있음
      • 반대로 단순히 WEEK를 반환하면 됨.
  • 그리고 다음으로 쉬운 경우를 테스트 한면 된다.
    • 예를 들면 한 규칙 충족여부를 검사하는 테스트이다.
      • 길이가 8글자 미만이고 나머지 규칙은 충족하는 암호의 강도는 NORMAL을 반환
      • 반대로 8글자 이상인 규칙만 충족하고 나머지는 충족하지 않는 강도는 WEEK를 반환
      • 위의 경우 길이가 8글자 이상인지 여부만 판단하는 로직을 작성하면 됨
    • 이런 식으로 각각의 경우에 한 조건 씩 검증하는 테스트를 수행하고 테스트를 통과시키면서 다음으로 쉬운 경우를 추가해 가는 것이 유리하다.
  • 한 번에 구현하는 시간이 짧아지면 디버깅에 유리하여 문제가 발생해도 원인을 빠르게 찾을 수 있음

예외 상황을 먼저 테스트해야 하는 이유

  • 다양한 예외 상황은 복잡한 if- else 블록을 동반하는 경우가 많음
  • 예외를 고려하지 않은 코드는 예외 상황을 반영하려면 코드의 구조를 뒤집거나 코드 중간에 예외 상황을 처리하기 위해 조건문을 중복 해서 추가하는 일이 벌어짐
    • 이는 코드를 더 복잡하게 만들어 버그 발생 가능성 증가 시킴
  • 따라서, 초반에 예외 상황을 테스트해서 이런 가능성을 줄여야 함.
  • TDD를 하는 동안 예외 상황을 찾고 테스트에 반영하면 예외 상황을 처리하지 않아 발생하는 버그도 줄여줌.

완급 조절

  • TDD를 처음 접할 때는 다음 단계에 따라 TDD를 익히면 됨
    1. 정해진 값을 리턴
    2. 값 비교를 이용해서 정해진 값을 리턴
    3. 다양한 테스트를 추가하면서 구현을 일반화
  • 단계적으로 나아가는 연습이 필요
  • 테스트→구현→확인

지속적인 리팩토링

  • 테스트를 통과한 뒤에는 리팩토링을 진행
  • 매번 리팩토링을 진행해야 하는 것은 아님, 적당한 후보에만 리팩토링 진행
    • 코드 중복은 대표적인 리팩토링 대상
    • 코드가 길어지면 메소드 추출과 같은 기법을 사용해서 메서드 이름으로 코드의 의미를 표현
  • TDD를 진행하는 과정에서 지속적으로 리팩토링을 진행하면 코드 가독성이 높아진다.
  • 코드의 가독성이 높을수록 개발자는 코드를 더 빠르게 분석하고 수정 요청이 있을 때 변경할 코드를 더욱 빠르게 찾을 수 있다.
    • 코드의 변경의 어려움을 줄여주어 향후 유지보수에 도움이 됨
    • 소프트웨어의 생존 시간이 길어질수록 지속적인 개선이 필요하며, 이를 위해 코드 변경이 자유로워야 하며, 이를 통해 요구사항을 제때 반영해야 한다.
    • 코드가 잘 변경되려면 변경하기 쉬운 구조를 가져야하며, 이를 위한 과정이 리팩토링이다.

테스트 대상 코드의 리팩토링시점

  • 상수를 변수로 바꾸거나 변수 이름을 변경하는 것과 같은 작은 리팩토링은 발견하면 바로 수행
  • 메서드 추출과 같이 메서드의 구조에 영향을 주는 리팩토링은 큰 틀에서 구현 흐름이 눈에 들어오기 시작한 뒤 진행한다.
    • 구조가 더 명확해진 후 메서드 추출 리팩토링 시도해야함

테스트 작성 순서 연습

  • 매달 비용을 지불해야 사용 가능한 유로 서비스가 있을 때, 다음 규칙에 따라 서비스 만료일을 결정함
    • 서비스를 사용하려면 매달 1만 원을 선불로 납부한다. 납부일 기중으로 한 달 뒤가 서비스 만료일이 됨
    • 2개월 이상 요금을 납부 할 수 있다.
    • 10만 원을 납부하면 서비스를 1년 제공한다.
  • 다음과 같이 납부한 금액 기준으로 서비스 만료일을 계산하는 기능을 TDD로 구현한다면
    • 먼저 테스트 클래스 이름을 정한다
    • 만료일을 뜻하는 expiry date + 계산을 의미하는 Calculator를 붙여 ExpiryDateCalculator 로 정함
1
2
3
4
package chap03

public class ExpiryDateCalculatorTest {
}

쉬운 것 부터 테스트

  • 이제 테스트 메서드를 추가. 테스트를 추가할 때는 다음 두가지 고려한다.
    • 구현하기 쉬운 것 부터 먼저 테스트
    • 예외 상황을 먼저 테스트

만료일 계산기에서는 1만 원을 납부하면 한 달 뒤 같은 날을 만료일로 계산하는 것이 가장 쉬움

  1. ex) 2024년 5월 1일에 1만 원을 납부하면, 만료일은 2024년 6월 1일이 된다.
  2. 계산에 필요한 값은 납부일과 납부액이고 결과는 계산된 만료일이다.
1
2
3
4
5
6
7
8
9
10
11
12
public class ExpiryDateCalculatorTest {
	@Test
	void 만원_납부하면_한달_뒤가_만료일이_됨(){
		LocalDate billingDate = LocalDate.of(2024,5,1);
		int payAmount = 10_000;
		
		ExpiryDateCalculator cal = new ExpiryDateCalculator();
		LocalDate expiryDate = cal.calculateExpiryDate(billingDate,payAmount);
		
		assertEquals(LocalDate.of(2024,6,1),expiryDate);
	}
}
  • 테스트를 통과시키려면 ExpiryDateCalculator# calculateExpiryDate()메서드가 2024-05-01에 해당하는 LocalDate를 리턴하면 됨.
1
2
3
4
5
6
7
8
9
package chap03

import java.time.LocalDate;

public class ExpiryDateCalculator {
	public calculateExpiryDate(LocalDate billingDate, int payAmount){
		return LocalDate.of(2024,6,1);
	}
}

예를 추가하면서 구현을 일반화

  • 이제 동일 조건의 예를 추가하면서 구현을 일반화시킨다.
    • 먼저 1만 원을 납부하는 예를 하나 더 추가한다.
    • ex2) 2024-04-03
    • 만료일은 2024-05-03이어야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Test
void 만원_납부하면_한달_뒤가_만료일이_됨(){
	LocalDate billingDate = LocalDate.of(2024,5,1);
	int payAmount = 10_000;
		
	ExpiryDateCalculator cal = new ExpiryDateCalculator();
	LocalDate expiryDate = cal.calculateExpiryDate(billingDate,payAmount);
		
	assertEquals(LocalDate.of(2024,6,1),expiryDate);
	
	//추가 예시
	LocalDate billingDate2 = LocalDate.of(2024,4,3);
	int payAmount2 = 10_000;
	
	ExpiryDateCalculator cal2 = new ExpiryDateCalculator();
	LocalDate expiryDate2 = cal2.calculateExpiryDate(billingDate2,payAmount2);
	
	assertEquals(LocalDate.of(2024,5,3),expiryDate2);
	
}

두 번째 assertEquals()에서 검증에 실패한다. 이제 구현을 고민할 차례

이 테스트를 통과시키기 위해 한 번 더 상수를 사용할지, 아니면 바로 구현을 일반화 할지?

이 예는 비교적 단순하므로 바로 구현을 일반화해도 된다. 아래 코드는 테스트를 통과시키기 위해 변경한 구현

1
2
3
4
5
public class ExpiryDateCalculator {
	public LocalDate calculateExpiryDate(LocalDate billingDate, int payAmount){
		return billingDate.plusMonth(1);
	}
}

위처럼 코드를 수정하고 테스트 통과 확인

코드 정리: 중복 제거

리팩토링할 시간!

ExpiryDateCalculator 클래스부터 보자

calculateExpiryDate() 메서드는 파라미터가 두 개이다.

아직은 파라미터가 두 개다.

파라미터가 더 많으면 객체 형태로 바꿔서 파라미터를 한 개로 만들겠지만, 아직 파라미터가 더 추가될지 알 수 없다.

발생하지도 않았는데 미리 단정 지어 코드를 수정할 필요는 없다.

테스트에 정리할 코드는 없을지? 테스트 메서드에는 다음 형태의 중복이 존재

1
2
3
4
5
6
7
LocalDate billingDate = 납부일;
        int payAmount = 납부액;

        ExpiryDateCalculator cal = new ExpiryDateCalculator();
        LocalDate expiryDate = cal.calculateExpiryDate(billingDate, payAmount);

        assertEquals(기대값, expiryDate);

보통은 중복을 제거하는 것이 좋지만, 테스트 코드의 중복 제거는 고민이 필요함

  • 왜냐면 각 테스트 메서드는 스스로 무엇을 테스트하는지 명확하게 설명할 수 있어야 검증 하기 때문이다.
  • 테스트 코드의 구현 중복을 기계적으로 제거하면 자칫 테스트 메서드가 검증하고 싶은 내용을 알아보기 힘들 수 있다.

일단 중복 제거를 해보고 테스트 코드가 여전히 자신을 설명하고 있는지 확인해본다.

메서드를 이용해서 중복을 제거한 결과이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class ExpiryDateCalculatorTest {
    @Test
    void 만원_납부하면_한달_뒤가_만료일이_됨() {
        assertExpiryDate(
                LocalDate.of(2024, 3, 1),
                10_000,
                LocalDate.of(2024, 4, 1)
        );

        assertExpiryDate(
                LocalDate.of(2024, 5, 5),
                10_000,
                LocalDate.of(2024, 6, 5)
        );
    }

    private void assertExpiryDate(LocalDate billingDate, int payAmount, LocalDate expectedExpiryDate) {
        ExpiryDateCalculator cal = new ExpiryDateCalculator();
        LocalDate realExpiryDate = cal.calculateExpiryDate(billingDate, payAmount);
        assertEquals(expectedExpiryDate, realExpiryDate);
    }
}

예외 사항 처리

쉬운 구현을 하나 했으니 이제 예외 상황을 찾아보자. 단순히 한 달 추가로 끝나지 않는 상황이 존재한다. 예를 들어 다음이 그런 예외 상황에 해당한다.

납부일 기준으로 다음 달의 같은 날이 만료일이 아닌 경우

이를 테스트로 추가

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Test
    void 납부일과_한달_뒤_일자가_같지_않음() {
        assertExpiryDate(
                LocalDate.of(2024, 1, 31),
                10_000,
                LocalDate.of(2024, 2, 29)
        );
        assertExpiryDate(
                LocalDate.of(2020, 1, 30),
                10_000,
                LocalDate.of(2020, 2, 29)
        );
        assertExpiryDate(
                LocalDate.of(2020, 5, 31),
                10_000,
                LocalDate.of(2020, 6, 30)
        );
    }

이 경우 LocalDate#plusMonth() 메서드가 알아서 한 달 추가 처리를 해준 것

다음 테스트 선택: 다시 예외 상황

그 다음으로 쉬운 예외 선택

  • 2만원을 지불하면 만료일이 두 달 뒤가 된다.
  • 3만원을 지불하면 만료일이 세 달 뒤가 된다.

다음 테스트를 추가하기 전에 리팩토링

만료일을 계산하는데 필요한 값이 세 개로 늘었다. 다음을 고민할 때가 됨.

  • calculateExpiryDate 메서드의 파라미터로 첫 납부일 추가
  • 첫 납부일, 납부일, 납부액을 담은 객체를 calculateExpiryDate 메서드에 전달

첫 납부일을 파라미터로 추가하면 파라미터가 세 개로 늘어난다.

  • 파라미터 개수는 적을수록 코드 가독성과 유지보수에 유리하므로 메서드의 파라미터 개수가 세 개 이상이면 객체로 바꿔 한 개로 줄이는 것을 고려해야 한다.
  • 이 장에서는 calculateExpiryDate메서드에 전달할 파라미터를 객체로 바꾸는 리팩토링을 먼저하고 그다음에 테스트를 추가 할 것

리팩토링을 위해 먼저 추가 된 PayDate 클래스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package chap03;

import java.time.LocalDate;

public class PayData {
    private LocalDate billingDate;
    private int payAmount;

    public PayData( LocalDate billingDate, int payAmount) {
        this.billingDate = billingDate;
        this.payAmount = payAmount;
    }

    public LocalDate getBillingDate() {
        return billingDate;
    }

    public int getPayAmount() {
        return payAmount;
    }
    
    public static Builder builder() {
        return new Builder();
    }

    public static class Builder {
        private LocalDate billingDate;
        private int payAmount;

        public Builder billingDate(LocalDate billingDate) {
            this.billingDate = billingDate;
            return this;
        }

        public Builder payAmount(int payAmount) {
            this.payAmount = payAmount;
            return this;
        }

        public PayData build() {
            return new PayData(billingDate, payAmount);
        }
    }
}

테스트 부분도 수정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class ExpiryDateCalculatorTest {
    @Test
    void 만원_납부하면_한달_뒤가_만료일이_됨() {
        assertExpiryDate(
                PayData.builder()
                        .billingDate(LocalDate.of(2024, 3, 1))
                        .payAmount(10_000)
                        .build(),
                LocalDate.of(2024, 4, 1)
        );

        assertExpiryDate(
                PayData.builder()
                        .billingDate(LocalDate.of(2024, 5, 5))
                        .payAmount(10_000)
                        .build(),
                LocalDate.of(2024, 6, 5)
        );
    }

    @Test
    void 납부일과_한달_뒤_일자가_같지_않음() {
        assertExpiryDate(
                PayData.builder()
                        .billingDate(LocalDate.of(2024, 1, 31))
                        .payAmount(10_000)
                        .build(),
                LocalDate.of(2024, 2, 29)
        );
        assertExpiryDate(
                PayData.builder()
                        .billingDate(LocalDate.of(2020, 1, 30))
                        .payAmount(10_000)
                        .build(),
                LocalDate.of(2020, 2, 29)
        );
        assertExpiryDate(
                PayData.builder()
                        .billingDate(LocalDate.of(2020, 5, 31))
                        .payAmount(10_000)
                        .build(),
                LocalDate.of(2020, 6, 30)
        );
    }

    private void assertExpiryDate(PayData payData, LocalDate expectedExpiryDate) {
        ExpiryDateCalculator cal = new ExpiryDateCalculator();
        LocalDate realExpiryDate = cal.calculateExpiryDate(payData);
        assertEquals(expectedExpiryDate, realExpiryDate);
    }
}

예외 상황 테스트 진행 계속

첫 납부일 기중으로 만료일 계산을 위해 리팩토링 했으니 테스트를 계속 진행

  • 첫 납부일이 2019-01-31이고 만료되는 2019-02-28에 1만 원을 납부하면 다음 만료일은 2019-03-31이다.
1
2
3
4
5
6
7
8
9
10
@Test
void 첫_납부일과_만료일_일자가_다를때_만원_납부() {
    PayData payData = PayData.builder()
            .firstBillingDate(LocalDate.of(2019, 1, 31)) // 납부일 추가
            .billingDate(LocalDate.of(2019, 2, 28))
            .payAmount(10_000)
            .build();

    assertExpiryDate(payData, LocalDate.of(2019, 3, 31));
}
  • 테스트는 실패하였다. 구현 코드를 수정해보자.

    1
    2
    3
    4
    5
    6
    7
    8
    
    public class ExpiryDateCalculator {
        public LocalDate calculateExpiryDate(PayData payData) {
            if(payData.getFirstBillingDate().equals(LocalDate.of(2019,1,31))) {
    						return LocalDate.of(2019,3,31);
    				}
    				return payData.getBillingDate().plugMonths(1);
        }
    }
    
  • 첫 번째 테스트는 통과했지만 두 테스트가 실패했다.

    • getFirstbillingDate가 null 체크를 구현 코드에 추가하였다.
  • 상수를 이용해서 테스트를 통과시켰으니 구현을 일반화할 차례다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    public class ExpiryDateCalculator {
        public LocalDate calculateExpiryDate(PayData payData) {
            if(payData.getFirstBillingDate() != null) {
    						LocalDate candidateExp = payDate.getBillingDate().plusMonths(1);
    						if(payData.getFirstBillingDate().getDayOfMonth() !=
    								candidateExp.getDatOhMonth()) {
    								return candidateExp.withDayOfMonth(
    										payData.getFirstBillingDate().getDayOfMonth());
    						}
    				}
    				return payData.getBillingDate().plugMonths(1);
        }
    }
    
  • 테스트는 통과하였다.

코드 정리: 상수를 변수로

  • plugMonths(1) 를 사용하였다. 1은 만료일을 계산할 때 추가할 개월 수를 의미한다.
  • 상수 1을 변수로 변경하자
1
2
3
4
5
6
7
8
9
10
11
12
public class ExpiryDateCalculator {
    public LocalDate calculateExpiryDate(PayData payData) {
        int addedMonths = 1;
        if(payData.getFirstBillingDate() != null) {
            LocalDate candidateExp = payData.getBillingDate().plusMonths(addedMonths);
            if(payData.getFirstBillingDate().getDayOfMonth() != candidateExp.getDayOfMonth()) {
                return candidateExp.withDayOfMonth(payData.getFirstBillingDate().getDayOfMonth());
            }
        }
        return payData.getBillingDate().plusMonths(addedMonths);
    }
}

다음 테스트 선택: 쉬운 테스트

  • 다음 테스트를 선택하자.

    • 2만 원을 지불하면 만료일이 두 달 뒤가 된다.
    • 3만 원을 지불하면 만료일이 석 달 뒤가 된다.
  • 테스트 코드를 추가해 보자

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    @Test
    void 이만원_이상_납부하면_비례해서_만료일_계산() {
        assertExpiryDate(
                PayData.builder()
                        .billingDate(LocalDate.of(2019, 3, 1))
                        .payAmount(20_000)
                        .build(),
                LocalDate.of(2019, 5, 1));
    }
    
  • 구현 코드를 수정해보자

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    public LocalDate calculateExpiryDate(PayData payData) {
    		// addedMonths를 금액에 따라 수정
    		int addedMonths = payData.getPayAmount() / 10_000;
      
        if(payDate.getFirstBillingDate() != null) {
    				LocalDate candidateExp = payDate.getBillingDate().plusMonths(addedMonths);
    				if(payData.getFirstBillingDate().getDayOfMonth() !=
    						candidateExp.getDatOhMonth()) {
    						return candidateExp.withDayOfMonth(
    								payData.getFirstBillingDate().getDayOfMonth());
    				}
    		}
    		return payData.getBillingDate().plugMonths(addedMonths);
    }
    

예외 상황 테스트 추가

  • 이번에 추가할 상황은 첫 납부일과 납부일의 일자가 다를 때 2만 원이상 납부한 경우이다.

    • 첫 납부일이 2019-01-31이고 만료되는 2019-02-28에 2만원을 납부하면 다음 만료일은 2019-04-30이다.
  • 테스트 코드를 추가하자

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    @Test
    void 첫_납부일과_만료일_일자가_다를때_이만원_이상_납부() {
        assertExpiryDate(
                PayData.builder()
                        .firstBillingDate(LocalDate.of(2019, 1, 31))
                        .billingDate(LocalDate.of(2019, 2, 28))
                        .payAmount(20_000)
                        .build(),
                LocalDate.of(2019, 4, 30));
    }
    
  • 이는 익셉션이 발생한다. 왜냐하면 4월에는 31일이 없는데 31일로 설정해서 발생한 것임을 알 수 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    public LocalDate calculateExpiryDate(PayData payData) {
    		int addedMonths = payData.getPayAmount() / 10_000;
      
        if(payData.getFirstBillingDate() != null) {
    				LocalDate candidateExp = payDate.getBillingDate().plusMonths(addedMonths);
    				if(payData.getFirstBillingDate().getDayOfMonth() !=
    						candidateExp.getDatOhMonth()) {
    						// 날짜가 잘못 계산되어 익셉션이 발생한다.
    						return candidateExp.withDayOfMonth(
    								payData.getFirstBillingDate().getDayOfMonth());
    				}
    		}
    		return payData.getBillingDate().plusMonths(addedMonths);
    }
    
  • 이 테스트를 통과시키려면 다음 조건을 확인해야 한다.

    • 후보 만료일이 포함된 달의 마지막 날 < 첫 납부일의 일자
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    public class ExpiryDateCalculator {
        public LocalDate calculateExpiryDate(PayData payData) {
            // addedMonths를 금액에 따라 수정
            int addedMonths = payData.getPayAmount() / 10_000;
            if(payData.getFirstBillingDate() != null) {
                LocalDate candidateExp = payData.getBillingDate().plusMonths(addedMonths);
                if(payData.getFirstBillingDate().getDayOfMonth() != candidateExp.getDayOfMonth()) {
                    if(YearMonth.from(candidateExp).lengthOfMonth() < payData.getFirstBillingDate().getDayOfMonth()) {
                        return candidateExp.withDayOfMonth(YearMonth.from(candidateExp).lengthOfMonth());
                    }
                    return candidateExp.withDayOfMonth(payData.getFirstBillingDate().getDayOfMonth());
                }
            }
            return payData.getBillingDate().plusMonths(addedMonths);
        }
    }
    

시작이 안 될 때는 단언부터 고민

테스트 코드를 작성하다 보면 시작이 잘 안 될 때가 있다. 이럴 땐 검증하는 코드부터 작성하기 시작하면 도움이 된다. 예를 들어 만료일 계산 기능의 경우 만료일을 검증하는 코드부터 작성해 보는 것이다.

  • 먼저 만료일을 어떻게 표현할지 결정해야 한다.
  • 만료일이므로 날짜를 표현하는 타입을 선택하면 좋을 것 같다.
  • 다음은 실제 만료일을 바꿀 차례다. 이 값은 만료일을 실제로 계산한 결과값을 갖는 변수로 바꿀 수 있다.
  • 어떤 객체의 메서드를 실행해서 계산 기능을 실행하도록 하자
  • 이제 두 가지를 정해야 한다.
    • cal의 타입 : 간단한 만료일 계산을 뜻하는 ExpiryDateCalculator로 정했다.
    • 파라미터 타입 : 만원을 납부했을 때 한 달 뒤가 만료일이 되는지를 테스트할 것이므로 납무일과 납부액을 전달한다.
  • 이렇게 테스트 코드를 어떻게 작성할지 감을 못 잡겠다면 검증 코드부터 시작해보자.

구현이 막히면

TDD를 작성하다 보면 어떻게 해야 할지 생각이 잘 나지 않거나 무언가 잘못한 것 같은 느낌이 들것이다. 이럴 땐 과감하게 코드를 지우고 미련 없이 다시 시작한다. 어떤 순서로 테스트 코드를 작성했는지 돌이켜보고 순서를 바꿔서 다시 진행한다. 다시 진행할때에는 다음을 상기한다.

  • 쉬운 테스트, 예외적인 테스트
  • 완급 조절