본문 바로가기
개발/TEST관련

테스트 주도 개발 3~9장

by ahoy~ 2020. 6. 15.

테스트가 다른 테스트에 영향을 주는지 판단하자

abstract class Money {
    protected int amount;
    protected String currency;

    public boolean equals(Object object){ // 같은지 확인
        Money money=(Money) object;
        return amount==money.amount &&getClass().equals(money.getClass());
    }

    abstract Money times(int multiplier); // 곱하기 함수
}

이러한 Money 추상 클래스가 있다고 합시다.
만약 times함수에 대한 테스트를 assertEquals를 통해 하게 된다면 equals함수를 통해 검사를 하게 됩니다.
equals함수의 테스트가 정확히 작동한다는 것에 대한 검증이 실패한다면 times함수에 대한 테스트에 영향을 주게 됩니다.
즉, 이러한 함수 간의 영향을 염두에 두는 것이 좋습니다.

테스트 시 유용한 디자인 패턴

값 객체 패턴(value object pattern)

값 객체에 대한 제약 사항은 객체의 인스턴스 변수가 생성자를 통해서 일단 설정된 후에는 결코 변하지 않는다는 것이다.(immutable과 개념이 유사한 것 같습니다.)

수표가 하나 있다고 칩시다.
여기에 5$를 설정하고 또 다른 수표에도 이 5$를 설정하였다고 합시다.
이로 발생할 수 있는 버그는 두번째 수표의 값을 변화시키는 바람에 첫번째 수표의 값이 변하는 것입니다.
이러한 버그는 많이 겪어봤을 것이라고 생각합니다.
이 버그 자체가 발생하지 못하도록 하는 것이 값 객체 패턴을 사용하는 것입니다.
값 객체의 연산의 결과는 새 객체를 반환해야만 합니다.

팩토리 메서드 패턴(factory method pattern)

Factory method는 부모(상위) 클래스에 알려지지 않은 구체 클래스를 생성하는 패턴이며. 자식(하위) 클래스가 어떤 객체를 생성할지를 결정하도록 하는 패턴입니다.
이는 객체의 생성 코드를 별도의 클래스/메서드로 분리함으로써 객체 생성의 변화에 대비하는 데 용이합니다.
예제를 살펴보겠습니다.

abstract class Money {
    static Money dollar(int amount){
        return new Dollar(amount,"USD");
    }

    static Money dollar(int amount){
        return new Dollar(amount,"USD");
    }

    static Money franc(int amount){
        return new Franc(amount,"CHF");
    }
    //물론 franc과 dollar생성자가 moneyFactory메서드나 MoneyFactory클래스로 같이 있는 것이 좋습니다.
}

class Dollar extends Money{
    public Dollar(int amount,String currency) {
        super(amount,currency);
    }
}

이와 같이 객체의 생성을 moneyFactory라는 별도의 메서드로 분리함으로서 확장성에 용이하게 합니다.
이렇게 되면 아래와 같이 테스트 코드에서 콘크리트 하위 클래스의 존재 사실을 분리해낼 수 있습니다.

    @Test
    public void testEquality(){
        assertTrue(Money.dollar(5).equals(Money.dollar(5)));
        assertFalse(Money.dollar(5).equals(Money.dollar(6)));
        assertTrue(Money.franc(5).equals(Money.franc(5)));
        assertFalse(Money.franc(5).equals(Money.franc(6)));
        assertFalse(Money.franc(5).equals(Money.dollar(5)));
    }
    // "Dollar dollar=new Dollar(5)"와 같은 코드가 사라졌습니다!

Tips for TDD

  1. 하나의 작업 중 수정해야하는 다른 작업이 발생할 경우 짧은 작업만 하자.(2번의 깊이로 다른 작업을 하게 되는 것은 금지) 2. TDD란 조종해나가는 과정이다. 불안하다면 보폭을 줄이고, 답답하다면 보폭을 조금 늘려도 괜찮다.
  2. 작업 리스트 중 작은 것 부터 해나가도록 하자.

'개발 > TEST관련' 카테고리의 다른 글

테스트에서의 서비스 추상화  (0) 2020.10.05
테스트 주도 개발 - 1~2장  (0) 2020.05.24
테스트 주도 개발  (2) 2020.05.24

댓글