[테스트 주도 개발] 25장_테스트 주도 개발 패턴

어떻게 테스트할 것인지에 대해 이야기하기 전에, 다음 질문들을 정리해보자.

  1. 테스트한다는 것은 무엇을 뜻하는가 ?
  2. 테스트를 언제 해야하는가 ?
  3. 테스트할 로직을 어떻게 고를 것인가 ?
  4. 테스트할 데이터를 어떻게 고를 것인가?
격리된 테스트

테스트는 전체 애플리케이션을 대상으로 하는 것 보다, 작은 스케일로 하는게 좋다.
각각의 테스트는 다른 테스트와 독립적이어야한다. 즉, 문제가 하나면 테스트도 하나만 실패해야하고 둘이면 두개만 실패해야한다.격리된 테스트가 내포하는 특징은, 테스트가 실행 순서에 독립적이게 된다는 것이다. 테스트를 격리하기 위한 작업은, 시스템이 응집도는 높고 결합도는 낮은 객체의 모음으로 구성되도록 한다.

테스트 목록

뭘 테스트 해야하나 ? 시작하기 전에 작석해야할 테스트 목록을 모두 적어둬라.
우선 구현할 필요가 있는 모든 오퍼레이션의 사용 예들을 적어라. 그 다음, 이미 존재하지 않는 오퍼레이션에 대해서는 해당 오퍼레이션의 null 버젼 (아무 일도 하지 않는 버젼) 을 리스트에 적어라. 마지막으로 깔끔한 코드를 얻기 위해 이번 작업을 끝내기 전에 반드시 해야할 리펙토링 목록을 적어라.

테스트 우선

테스트는 언제 작성하는 것이 좋은가 ? 테스트 대상이 되는 코드를 작성하기 직전에 작성해라.

assertion 우선

테스트 작성할 때 단언은 언제쯤 쓸까 ? 단언를 먼저 쓰고 시작하라.
단언을 먼저 작성하면 작업을 단순하게 만들 수 있다. 소켓을 통해 다른 시스템과 통신하려고 한다고 해보자. 통신을 마친 후 소켓은 닫혀 있고, 소켓에서 문자열 abc 를 읽어와야한다고 하자.

1
2
3
4
5
@Test
public void testCompleteTransaction(){
assertTrue(reader.isClosed());
assertEquals("abc", reply.contents());
}

다음으로, reply 는 어디에서 오나? socket 이다.

1
2
3
4
5
6
@Test
void testCompleteTransaction() {
Buffer reply = reader.contents();
assertTrue(reader.isClosed());
assertEquals("abc", reply.contents());
}

다음으로, 소켓은 어디에서 나오나 ? 다음 같이, 서버 접속할 때 생성된다.

1
2
3
4
5
6
7
@Test
void testCompleteTransaction() {
Socket reader = new Socket("localhost", defaultPort());
Buffer reply = reader.contents();
assertTrue(reader.isClosed());
assertEquals("abc", reply.contents());
}

물론 다음 처럼, 서버를 먼저 열어야한다.

1
2
3
4
5
6
7
8
@Test
void testCompleteTransaction() {
Server writer = new Server(defaultPort(), "abc");
Socket reader = new Socket("localhost", defaultPort());
Buffer reply = reader.contents();
assertTrue(reader.isClosed());
assertEquals("abc", reply.contents());
}
테스트 데이터

테스트할 때 어떤 데이터를 사용해야하는가 ? 테스트를 읽을 때 쉽고 따라하기 좋은 데이터를 사용해라.
만역, plus() 메서드를 구현한다면 2+2 대신에, 2+3 을 써라.

명백한 데이터

데이터의 의도를 어떻게 표현하나 ? 테스트 자체에 예상되는 값과 실제 값을 포함하고, 이 둘 사이의 관계를 드러내기 위해 노력해라.
입력으로 사용된 숫자와 예상되는 결과 사이의 관계를 드러내라. 프로그래밍이 쉬워지고 단언 부분에 수식을 써놓으면 다음에 무엇을 할지 쉽게 알게 된다.


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

Comments