[Test] 테스트 주도 개발 (15 ~ 16장)

DaeHoon·2022년 11월 5일
0

TDD

목록 보기
4/9

15. 서로 다른 통화 더하기

$5 + 10CHF = $10

@Test
  public void testMixedAddition(){
    Money fiveBucks = Money.dollar(5);
    Money tenFranc = Money.franc(10);
    Bank bank = new Bank();
    bank.addRate("CHF", "USD", 2);
    Money result = bank.reduce(fiveBucks.plus(tenFranc), "USD");
    assertEquals(Money.dollar(10), result);
  }
  • $5 + 10CHF = $10를 수행하기 위한 테스트를 작성한다.
  • 테스트는 실패한다. reduce에서 환율을 적용하지 않아 값이 15가 나오기 때문
Sum
  public Money reduce(Bank bank, String to){
    int amount = augend.reduce(bank, to).amount + addend.reduce(bank, to).amount;
    return new Money(amount, to);
  }
  • Sum의 reduce에서 환율을 적용하게 만들어주자.
  • 초록 막대

Money -> Expression

Sum
public class Sum implements Expression{
  Expression augend;
  Expression addend;
	
  Sum(Expression augend, Expression addend){
    this.augend = augend;
    this.addend = addend;
  }
...
}
Money
  Expression plus(Expression addend){
    return new Sum(this, addend);
  }
  
  Expression times(int multiplier){
    return new Money(amount* multiplier, currency);
  }
  • Money에서도 마찬가지로 Expression으로 변경된다.
  @Test
  public void testMixedAddition(){
    Expression fiveBucks = Money.dollar(5);
    Expression tenFranc = Money.franc(10);
    Bank bank = new Bank();
    bank.addRate("CHF", "USD", 2);
    Money result = bank.reduce(fiveBucks.plus(tenFranc), "USD");
    assertEquals(Money.dollar(10), result);
  }
  • Money를 Expression으로 변경해준다.
  • Expression에 plus가 정의되어있지 않아 컴파일이 안된다.
Expression
public interface Expression {
  Expression plus(Expression addend);
}

Money
  public Expression plus(Expression addend){
    return new Sum(this, addend);
  }

Sum
  public Expression plus(Expression addend) {
    return null;
  }
  • plus 함수를 정의
  • Money의 접근자를 public으로 변경해준다.
  • Sum의 plus를 스텁 구현으로 구현해준다.
  • 테스트는 다시 초록상태

우리는

  • 원하는 테스트를 작성하고, 한 단계에 달성할 수 있도록 뒤로 물렀다.
  • 좀더 추상적인 선언을 통해 가지에서 뿌리(애초의 테스트 케이스)로 일반화했다.
  • 변경 후(Expression fiveBucks), 그 영향을 받은 다른 부분들의 변경하기 위해 컴파일러의 지시를 따랐다. (Expression에 plus()를 추가하기 등등)

16. 드디어, 추상화

Sum.plus()

  @Test
  public void testSumPlusMoney(){
    Expression fiveBucks = Money.dollar(5);
    Expression tenFranc = Money.franc(10);
    Bank bank = new Bank();
    bank.addRate("CHF", "USD", 2);
    Expression sum = new Sum(fiveBucks, tenFranc).plus(fiveBucks);
    Money result = bank.reduce(sum, "USD");
    assertEquals(Money.dollar(15), result);
  }
  • expression의 reduce가 스텁으로 되어있어 nullpointerException 발생
Sum
  @Override
  public Expression plus(Expression addend) {
    return new Sum(this, addend);
  }
  • Sum.plus() 구현

TDD로 구현할 때?

  • TDD로 구현할 때 테스트 코드의 줄 수와 모델 코드의 줄 수가 거의 비슷한 상태로 끝난다.
  • TDD가 경제적이기 위해서는 매일 만들어내는 코드의 줄 수가 두 배가 되거나 동일한 기능을 해내야한다.
  • TDD가 자신의 방법에 비해 어떻게 다른지 직접 측정해 보아야 한다. 이 때 디버깅, 통합 작업, 다른 살마에게 설명하는데 걸리는 시간 등의 요소를 반드시 포함해야 한다.

Expression.times()

  @Test
  public void testSumTimes(){
    Expression fiveBucks = Money.dollar(5);
    Expression tenFranc = Money.franc(10);
    Bank bank = new Bank();
    bank.addRate("CHF", "USD", 2);
    Expression sum = new Sum(fiveBucks, tenFranc).times(2);
    Money result = bank.reduce(sum, "USD");
    assertEquals(Money.dollar(20), result);
  }
  • 테스트는 컴파일 조자 되지 않는다.
Sum
Expression times(int multiplier){
    return new Sum(augend.times(multiplier), addend.times(multiplier));
  }
  • Sum에 times을 구현해보자.
  • Expression 타입으로 지정된 augend, addend에 times 메서드가 없으므로 컴파일이 되지 않는다.
public interface Expression {
  Expression times(int multiplier);
  • Expression에 times 메서드 선언
  • 이후 times를 구현한 메서드 접근자를 public으로 바꿔준다.
  • 테스트는 통과된다

$5 +$5도 통과할까?

  @Test
  public void testPlusSameCurrencyReturnsMoney(){
    Expression sum = Money.dollar(1).plus(Money.dollar(1));
    assertTrue(sum instanceof Money);
  }
  • 실패한다.
  • 인자가 Money일 경우에 인자의 통화를 확인하는 깔끔한 방법이 없다. 테스트를 삭제해주자.

우리는

  • 미래에 코드를 읽을 다른 사람들을 염두에 둔 테스트를 작성했다.
  • TDD와 여러분의 현재 개발 스타일을 비교해 볼 수 있는 실험 방법을 제시했다.
  • 또 한 번 선언부에 대한 수정이 시스템 나머지 부분으로 번져갔고, 문제를 고치기 위해 역시 컴파일러의 조언을 따랐다.
  • 잠시 실험을 시도했는데, 제대로 되지 않아서 버렸다.
profile
평범한 백엔드 개발자

0개의 댓글