[테스트 주도 개발] 6장_돌아온 모두를 위한 평등

5장에서 테스트를 빨리 통과하기 위해 코드를 복사해서 붙이는 죄를 저질렀다. 이제 청소할 시간이다.
Money 클래스가 공통의 equals 코드를 갖게 하면 어떨까 ? 간단한 것부터 시작하자.

1
2
class Money {
}

테스트는 여전히 돌아간다. Dollar 가 Money 를 상속받아도 여전히 어떤 것도 깨지지 않는다.

1
2
3
public class Dollar extends Money {
...
}

이제 amount 인스턴스 변수를 Money 로 옮길 수 있다.

1
2
3
class Money {
protected int amount;
}

하위 클래스에서도 변수를 볼 수 있도록, 가시성을 private 에서 protected 로 변경했다.
이제, equals() 를 위로 올릴 수 있다. 우선, 임시 변수 선언하는 부분을 변경하자.

1
2
3
4
5
public boolean equals(Object object) {
Money dollar = (Dollar) object;

return amount == dollar.amount;
}

모든 테스트가 잘 돈다. 이제 cast 부부을 변경하자.

1
2
3
4
5
public boolean equals(Object object) {
Money dollar = (Money) object;

return amount == dollar.amount;
}

좀 더 원활한 의사소통을 위해, 임시 변수의 이름을 변경하자.

1
2
3
4
5
public boolean equals(Object object) {
Money money = (Money) object;

return amount == money.amount;
}

이제 이 메서드를 Dollar 에서 Money 로 옮길 수 있다.

1
2
3
4
5
6
7
8
9
class Money {
protected int amount;

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

return amount == money.amount;
}
}

이제는 Franc.equals() 를 제거해야한다. 일단 동치성 테스트가 Franc 끼리의 비교에 대해서는 아직 다루지 않았다. 우리는 코드를 변경하기 전에 그곳에 있어야 했던 테스트를 먼저 작성할 것이다. 리펙토링 전에 테스트를 먼저 하자.

1
2
3
4
5
6
7
@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)));
}

또 중복이다.

1
2
3
4
public class Franc extends Money {
private int amount;
...
}

Money 클래스에 있는 필드를 이용하면, amount 필드를 제거할 수 있다.

1
2
3
public class Franc extends Money {
...
}

Franc.equals() 는 Money.equals() 와 비슷해 보인다. 이 두 부분을 똑같이 만들면 프로그램의 의미를 변화시키지 않고도 Franc.equals() 를 완전히 지울 수 있다. 우선 임시 변수 선언 부분부터 고치자.

1
2
3
4
5
public boolean equals(Object object) {
Money franc = (Franc) object;

return amount == franc.amount;
}

다음엔 cast.

1
2
3
4
5
public boolean equals(Object object) {
Money franc = (Money) object;

return amount == franc.amount;
}

임시 변수의 임름도 상위 클래스에 맞게 고치자.

1
2
3
4
5
public boolean equals(Object object) {
Money money = (Money) object;

return amount == money.amount;
}

이제 Franc.equals() 는 Money.equals() 와 동일하므로, Franc 의 불필요한 코드를 제거하자.


테스트 주도 개발 <켄트 벡>

Comments