Developer Log
  • Wiki
  • Books
    • 리눅스 시스템 프로그래밍
      • 핵심 개념 소개
        • 시스템 프로그래밍
        • API와 ABI
        • 리눅스 프로그래밍의 개념
          • 파일과 파일시스템
          • 프로세스
          • 사용자와 그룹
          • 권한
          • 시그널
          • 프로세스간 통신
          • 에러 처리
    • 데이터 베이스 첫걸음
      • 데이터베이스란
        • 데이터베이스의 역할을 생각해 보자
          • 우리와 데이터베이스의 관계
          • 데이터베이스의 기본 기능
          • 데이터베이스 종류
      • 관계형 데이터베이스란
        • 대표적인 DBMS를 알아보자
          • 관계형 데이터베이스란
          • SQL 기초 지식
          • 관계형 데이터베이스를 다루기 위한 사전 지식
      • 데이터베이스에 얽힌 돈 이야기
        • 초기비용과 운영비용을 생각하자
      • 데이터베이스와 아키텍처 구성
        • 다중화에 대해 생각해보자
          • 아키텍처란
          • 데이터베이스의 아키텍처
            • 역사와 개요
              • Stand-alone
              • 클라이언트/서버
              • Web 3계층
            • 가용성과 확장성의 확보
          • DB 서버의 다중화
            • 클러스터링
            • 리플리케이션
          • 성능을 추구하기 위한 다중화 - Shared Nothing
          • 적합한 아키텍처를 설계하기 위해
      • DBMS를 조작할 때 필요한 기본 지식
        • MySQL 설치해보자
        • MySQL과 커넥션 만들기, 데이터베이스에 전화걸기
        • SQL과 관리 명령의 차이
        • 관계형 데이터베이스의 계층
      • SQL 문의 기본
        • SELECT 문으로 테이블 내용을 살펴보자
        • SELECT 문을 응용해보자
        • 데이터를 갱신, 삽입, 제거해보자
        • 뷰를 작성하고 복수 테이블에서 선택해보자
      • 트랜잭션과 동시성 제어
      • 테이블 설계의 기초
      • 백업과 복구
      • 성능을 생각하자
    • 개발자가 반드시 정복해야 할 객체 지향과 디자인 패턴
      • 객체 지향
        • 들어가기
        • 객체 지향
        • 다형성과 추상 타입
        • 재사용: 상속보단 조립
      • 설계 원칙 / DI와 서비스 로케이터
        • 설계 원칙: SOLID
          • 단일 책임 원칙(Single Responsibility Principle)
          • 개방 폐쇄 원칙(Open - Closed Principle)
          • 리스코프 치환 원칙(Liskov Substitution Principle)
          • 인터페이스 분리 원칙(Interface Segregation Principle)
          • 의존 역전 원칙(Dependency Inversion Principle)
          • SOLID 정리
        • DI(Dependency Injection)와 서비스 로케이터
      • 주요 디자인 패턴
        • 디지인 패턴이란?
        • 전략(Strategy) 패턴
        • 템플릿 메서드(Template Method) 패턴
        • 상태(State) 패턴
        • 데코레이터(Decorator) 패턴
        • 프록시(Proxy) 패턴
        • 어댑터(Adapter) 패턴
        • 옵저버(Observer) 패턴
        • 미디에이터(Mediator) 패턴
        • 파사드(Facade) 패턴
        • 컴포지트(Composite) 패턴
        • 널(Null) 객체 패턴
        • 팩토리 메서드 패턴
        • 커맨드 패턴
        • 추상 팩토리 패턴
    • 테스트 주도 개발
      • 1부
        • 다중 통화를 지원하는 Money 객체
        • 타락한 객체
        • 모두를 위한 평등
        • 프라이버시
        • 솔직히 말하자면
        • 돌아온 '모두를 위한 평등'
        • 사과와 오렌지
Powered by GitBook
On this page
  • Money 공통 클래스
  • Money Equals
  • 적절한 테스트가 없는 코드에서의 TDD
  • 동일한 중복코드로 만들어 제거하

Was this helpful?

  1. Books
  2. 테스트 주도 개발
  3. 1부

돌아온 '모두를 위한 평등'

앞 과정에서 하나의 테스트를 통과하기 위해 엄청난 중복 코드를 만들었기 때문에, 이제 중복 코드를 제거하는 리팩토링을 할 시간이다.

우선, Dollar와 Franc 두 클래스에서 Money 라는 공통 클래스를 구성하고 equals 코드를 갖게 하면 어떨까?

할일 목록을 업데이트 하고, 하나씩 진행해보자.

  • $5 + 10CHF = $10(환율이 2:1 일 경우)

  • $5 * 2 = 10$

  • amount를 private으로 만들기

  • Dollar 부작용(side effect)?

  • Money 반올림?

  • equals()

  • hashCode()

  • Equal null

  • Equal object

  • 5CHF * 2 = 10CHF

  • Dollar/Franc 중복

  • 공용 equals

  • 공용 time

Money 공통 클래스

공통 Money 클래스를 생성하고 테스트를 진행해보자.

public class Money {
}

무리없이 테스트가 통과한다.

다음으로 Dollar가 Money를 상속하도록 변경하고 테스트해본다.

public class Dollar extends Money {
    private int amount;

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

    }

    public Dollar times(int multiplier) {
        return new Dollar(amount * multiplier);

    }

    public boolean equals(Object object) {
        Dollar dollar = (Dollar) object;
        return amount == dollar.amount;

    }

}

테스트 모두 잘 동작한다.

이제 amount 인스턴스 변수를 Money 로 옮기며 Dollar 클래스에서 참조 가능하게끔 protected 접근 범위로 변경한다.

public class Money {
    protected int amount;
    
}

Money Equals

이어서, equals() 메서드를 Money 클래스로 옮기는 작업을 천천히 진행해보자.

첫 번째로 임시변수 타입을 상위 타입으로 변경한다.

public boolean equals(Object object) {
    Money dollar = (Dollar) object;
    return amount == dollar.amount;

}

모든 테스트는 여전히 잘 돈다.

다음으로 캐스팅(cast) 타입도 변경해서 테스트 해보자.

public boolean equals(Object object) {
    Money dollar = (Money) object;
    return amount == dollar.amount;

}

테스트는 잘 동작하며, 조금 더 명확하게 변수명을 money로 변경해보자.

public boolean equals(Object object) {
    Money money = (Money) object;
    return amount == money.amount;

}

마지막으 equals 메서드를 Money 클래스로 옮겨보자.

public class Money {
    protected int amount;

    public boolean equals(Object object) {
        Money dollar = (Money) object;
        return amount == dollar.amount;

    }

}

적절한 테스트가 없는 코드에서의 TDD

Franc equals 도 제거해야 할 차례이다. 여기서 문제는 Franc 객체간의 동치성 테스트를 하지 않았다는 점이다.

적절한 테스트가 없는 경우, 어떻게 접근해야 할까?

충분한 테스트가 존재하지 않는다면 지원 테스트가 잘 갖춰지지 않은 리팩토링을 만날 수 밖에 없다. 결국, 리팩토링하면서 실수하였는데도 불구하고 여전히 테스트를 통과하는 위험을 초래할 수 있다.

어쩔 수 없다. 개발자 스스로가 리팩토링 전에 있으면 좋을 것이라고 생각하는 테스트를 작성하 그 범위를 좁혀 나가야만 한다.

Franc equals 경우에는 Dollar 동치성 테스트를 복사하면 된다.

@Test
void testEquality() {
    assertTrue(new Dollar(5).equals(new Dollar(5)));
    assertFalse(new Dollar(5).equals(new Dollar(6)));
    assertTrue(new Franc(5).equals(new Franc(5)));
    assertFalse(new Franc(5).equals(new Franc(6)));
    
}

동일한 중복코드로 만들어 제거하

이제 Dollar equals 와 동일하게 Franc equals 도 점진적으로 제거해 나간다.

Money 타입을 상속받고, amount 인스턴스 변수를 제거해보자.

public class Franc extends Money {
    public Franc(int amount) {
        this.amount = amount;

    }

    public Franc times(int multiplier) {
        return new Franc(amount * multiplier);

    }

    public boolean equals(Object object) {
        Franc franc = (Franc) object;
        return amount == franc.amount;

    }

}

테스트는 여전히 잘 동작한다.

이제 Franc.equals() 와 Money.equals() 가 비슷해보이며, 완전히 동일하게 만들 수 있다면 프로그램의 의미를 변화시키지 않고 Franc.equals() 를 제거할 수 있을 것이다.

임시변수의 Franc 타입을 Money 로 변경해보자.

public boolean equals(Object object) {
    Money franc = (Franc) object;
    return amount == franc.amount;

}

다음으로 캐스팅도 상위 타입으로 변경한다.

public boolean equals(Object object) {
    Money franc = (Money) object;
    return amount == franc.amount;

}

결과적으로, Money.equals() 와 Franc.equals()는 완벽히 동일하기 때문에 Franc.equals()를 제거할 수 있다.

public boolean equals(Object object) {
    Money money = (Money) object;
    return amount == money.amount;

}

테스트 또한, 잘 동작하고 있다. 할일 목록에서 하나 더 선을 그을 수 있게 되었다.

  • $5 + 10CHF = $10(환율이 2:1 일 경우)

  • $5 * 2 = 10$

  • amount를 private으로 만들기

  • Dollar 부작용(side effect)?

  • Money 반올림?

  • equals()

  • hashCode()

  • Equal null

  • Equal object

  • 5CHF * 2 = 10CHF

  • Dollar/Franc 중복

  • 공용 equals

  • 공용 time

  • Franc과 Dollar 비교하기

Previous솔직히 말하자면Next사과와 오렌지

Last updated 5 years ago

Was this helpful?