1장. 다중 통화를 지원하는 Money 객체

변주한·2022년 6월 4일
0

들어가기전에 명심할 단계는

  1. 작은테스트를 하나 추가한다.
  2. 모든 테스트를 실행해서 테스트가 실패하는 것을 확인한다.
  3. 조금 수정한다.
  4. 모든 테스트를 실행해서 테스트가 성공하는 것을 확인한다.
  5. 중복을 제거하기 위해 리팩토링을 한다.

이다.

자 그럼 해당 과정을 기억하고 들어가보자!


다음과 같은 보고서가 있다고 하자.

종목가격합계
IBM100025USD25000USD
Novartis400150CHF60000CHF
합계65000USD

다중 통화를 지원하는 보고서를 만들려면 통화 단위를 추가해야 한다.

기준변환환율
CHFUSD1.5
  • 통화가 다른 두 금액을 더해서 주어진 환율에 맞게 변한 금액을 결과로 얻을 수 있어야 한다.

  • 어떤 금액(주가)을 어떤 수 (주식의 수)에 곱한 금액을 결과로 얻을 수 있어야 한다.

우선 어떤 테스트가 필요할까?

	@Test
    public void testMultiplication(){
        Dollar five = new Dollar(5);
        five.times(2);
        Assertions.assertEquals(10, five.amount);
    }

실패하는 테스트가 주어진 상태이고 최대한 빨리 초록 막대를 보고 싶을 뿐이다.

$5 + 10 CHF = $10(환율이 2:1일 경우)
$5 X 2 = $10
amount를 private으로 만들기
Dollar 부작용(side effect)?
Money 반올림

일단 테스트조차 진행이 안될텐데 아래의 목록이 그 이유이다.

  • Dollar 클래스가 없음
  • 생성자가 없음
  • times(int) 메서드가 없음
  • amount 필드가 없음

이 목록에 따라 일단 테스트 실행을 위해 클래스 정의를 시작하자

public class Dollar {

    int amount;

    public Dollar(int amount) {
        
    }

    public void times(int multiplier) {
        
    }
}

테스트를 실행해서 테스트가 실패하는 모습을 볼 수 있게 됐다.

슬프다... 빨간 막대다.

우리 문제는 다중 통화 구현에서 이 테스트를 통과시킨 후 나머지 테스트들도 통과시키기로 변형된 것이다. 훨씬 간단하다. 범위도 훨씬 적어서 걱정이 줄었다.

일단 적절한 방법인지는 모르겠고 일단 통과부터 시켜보자

...
이렇게 하면 되겠지만 뭔가 존나 찝찝하다

public class Dollar {

    int amount = 10;
    
 .
 .
 .
}

이렇게 해도 당장에 10이라는 걸 2랑 5로 나누어 놨기 때문에 다른 테스트에서 통과는 되겠지만 아직 찝찝하다

public class Dollar {

    int amount = 2 * 5;
    
 .
 .
 .
}

그럼 times()메서드 안으로 해당 내용을 옮겨보면 어떨까?
당장에 times를 사용해서 테스트 마지막 값을 정하니 맞겠지만 역시나 찝찝이다.

public class Dollar {

    int amount;

    public void times(int multiplier) {
        this.amount = 5 * 2;
    }
}

5를 어디서 얻을 수 있을까? 이건 생성자에서 넘어오는 값이니 이걸 다음과 같이 amount변수에 저장하면

	public Dollar(int amount) {
        this.amount = amount;
    }

앞전에본 5 * 2에서 5라는 상수를 amount로 대체한다면 그리고 2라는 값을 인자로 대체해준다면 뭔가 그럴듯하게 드디어 첫번째 테스트를 완수 시킬수 있다.

	public void times(int multiplier) {
        this.amount *= multiplier;
    }

현재 Dollar class이다.

public class Dollar {

    int amount;

    public Dollar(int amount) {
        this.amount = amount;
    }

    public void times(int multiplier) {
        this.amount *= multiplier;
    }
}

$5 + 10 CHF = $10(환율이 2:1일 경우)
$5 X 2 = $10
amount를 private으로 만들기
Dollar 부작용(side effect)?
Money 반올림

되돌이켜보면 우리는 다음 작업들을 했다.

  • 우리가 알고 있는 작업해야 할 테스트 목록을 만들었다.
  • 오퍼레이션이 외부에서 어떻게 보이길 원하는지 말해주는 이야기를 코드로 표현했다.
  • JUnit에 대한 상세한 사항들은 잠시 무시하기로 했다.
  • 스텁 구현을 통해 테스트를 컴파일 했다.
  • 끔찍한 죄악을 범하여 테스트를 통과시켰다.
  • 돌아가는 코드에서 상수를 변수로 변경하여 점진적으로 일반화했다.
  • 새로운 할일들을 한번에 처리하는 대신 할 일 목록에 추가하고 넘어갔다.

profile
늦었지만 꾸준히

0개의 댓글