김동형수 개발기

테스트 주도 개발 - 3부 25장 본문

책 스터디/[완료] 테스트 주도 개발

테스트 주도 개발 - 3부 25장

김동형수 2022. 10. 19. 00:26

3부 테스트 주도 개발의 패턴

TDD트릭, 디자인 패턴, 리펙토링에 대해서 이야기한다.

 

25장. 테스트 주도 개발 패턴

테스트 전략에 관한 질문

  • 테스트한다는 것은 무엇을 뜻하는가?
  • 테스트를 언제 해야 하는가?
  • 테스트할 로직을 어떻게 고를 것인가?
  • 테스트할 데이터를 어떻게 고를 것인가?

테스트

보통의 사람들은 작은 변화가 있으면 테스트하지 않고 릴리즈 하지 않는다.

스타일의 영향도

노드 사이의 화살표는 첫번째 노드가 높아지면 두번째 노드도 같이 높아지게 된다는걸 의미하고 동그라미가 그려진 화살표는 첫 번째 노드가 높아지면 반대로 두 번째 노드가 낮아지게 된다는 것을 의미한다.

 

스트레스가 증가하면 어떻게 될까?

 

 

스트레스가 많아지면 테스트는 더 뜸하게 되고 에러는 점점 많아질 것이다. 에러가 많아지면 스트레스를 받게 된다. 씻어내고 다시 반복하라

 

이 고리에서 빠져나오는 방법은 새로운 요소 도입, 기존 요소와 바꿔치기, 화살표를 바꾼다. 이 경우엔 '테스트'를 '자동화된 테스트'로 치환한다.

 

자동화된 테스트를 이용하면 스트레스의 강도를 조절할 수 있다.

 

격리된 테스트

테스트는 서로 영향력이 없어야 한다.

저자가 자동화 테스트를 하면서 얻은 교훈, 하나는 테스트가 충분히 빨라서 내가 직접 자주 실행할 수 있게끔 만들자는 것이다.

둘째는 많은 양의 실패결과가 반드시 어마어마한 양의 문제를 의미하는 것은 아니라는 점.

테스트는 전체 어플리케이션 대상으로 하는 것 보다 좀 더 작은 스케일로 하는 게 좋다.

 

격리된 테스트가 암묵적으로 내포하는 특징 중 하나는 테스트가 실행 순서에 독릭접이게 된다는 점이다.

테스트 데이터 공유, 응집도를 높이고 결합도를 낮추는 설계가 좋다.

 

테스트 목록

테스트를 하기전에 테스트 목록을 모두 적어둘 것.

목표에서 벗어나지 않고 집중할 수 있는 한 가지 전략은 모든 걸 머리속에 넣어 두는 것이다.

할일을 '지금'할 것과 '나중에'할 것 분류를 한다.

테스트 개발에 적용해보면 아래와 같다.

테스트 목록을 적는다.

구현할 필요가 있는 모든 오퍼레이션의 사용예들을 적는다.

존재하지 않는 오퍼레이션에 대해서는 해당 오퍼레이션의 널 버전을 적느다.

리펙토링 목록을 적는다.

테스트의 윤곽만 잡는 대신, 한 걸음 더 나아가 테스트를 전부 구현할 수도 있다.

 

테스트 우선

테스트를 언제 작성하는 것이 좋을까? 테스트 대상이 되는 코드를 작성하기 직전에 작성하는 것이 좋다. 코드를 작성한 후에는 테스트를 만들지 않을 것이다. 프로그래머로서 우리의 목표는 기능이 실행되도록 만드는 것이다. 하지만 또 한편으로는 프로그램의 설계에 대해 생각해볼 시간도 필요하고 작업 범위를 조절할 방법도 필요할 것이다. 

 

단언 우선

테스트를 작성할 때 단언(assert)를 언제쯤 쓸까? 단언을 제일 먼저 쓰고 시작하라.

  • 시스템을 개발할 때 무슨 일부터 하는가? 완료된 시스템이 어떨 거라고 알려주는 이야기부터 작성한다.
  • 특정 기능을 개발할 때 무슨 일부터 하는가? 기능이 완료되면 통과할 수 있는 테스트부터 작성한다.
  • 테스트를 개발할 때 무슨 일부터 하는가? 완료될 때 통과해야 할 단언부터 작성한다. 

단언을 먼저 작성하면 작업을 단순하게 만드는 강력한 효과를 볼 수 있다. 구현에대해 전혀 고려하지 않고 테스트만 작성할 때도 사실 우리는 몇 가지 문제들을 한번에 해결하는 것이다. 

  • 테스트하고자 하는 기능이 어디에 속하는 걸까? 기존의 메서드를 수정해야 하나, 기존의 클래스에 새로운 메서드를 추가해야 하나, 아니면 이름이 같은 메서드를 새 장소에? 또는 새 클래스에?
  • 메서드 이름은 뭐라고 해야 하나?
  • 올바른 결과를 어떤 식으로 검사할 것인가?
  • 이 테스트가 제안하는 또 다른 테스트에는 뭐가 있을까? 

이 문제를 한번에 잘 해결하기에는 쉽지가 않다.  '올바른 결과는 무엇인가?', '어떤 식으로 검사할 것인가?;는 나머지 문제에서 쉽게 분리할 수 있다. 

 

테스트 데이터

테스트할 때 어떤 데이터를 사용해야 하는가? 테스트를 읽을 때 쉽고 따라가기 좋을 만한 데이터를 사용하라. 데이터 작성에도 청중이 존재한다. 단지 데이터 값을 산발하기 위해 데이터 값을 산발하지 마라. 데이터 간에 차이가 있다면 그 속에 어떤 의미가 있어야 한다. (1과 2사이에 어떠한 개념적 차이도 없다면 1을 사용하라)

테스트 데이터 패턴이 완전한 확신을 얻지 않아도 되는 라이선스는 아니다. 만약 시스템이 여러 입력을 다루어야 한다면 테스트 역시 여러 입력을 반영해야 한다. 하지만 세 항목만으로 동일한 설계와 구현을 이끌어낼 수 있다면 굳이 항목을 열 개나 나열할 필요는 없다.

테스트 데이터 패턴의 한 가지 트릭은 여러 의미를 담는 동일한 상수를 쓰지 않는 것이다. 만약 plus() 메서드를 구현하려고 한다면 고전적 예제인 2+2 혹은 1+1을 쓰고 싶을 것이다. 만약 구현에서 인자의 순서가 뒤집힌다면 어떻게 될까? (plus()에서야 순서가 뒤집혀도 상관이 없겠지만 다른 메서드는 아닐수도 있다 )우리가 첫 번째 인자로 2를 썼다면 두 번째 인자는 3을 써야 한다. 테스트 데이터에 대한 대안은 실제 세상에서 얻어진 실제 데이터를 사용하는 것이다. 실제 데이터는 다음과 같은 경우에 유용하다. 

  • 실제 실행을 통해 수집한 외부 이벤트의 결과를 이용하여 실시간 시스템을 테스트하고자 하는 경우.
  • 예전 시스템의 출력과 현재 시스템의 출력을 비교하고자 하는 경우 (병렬 테스팅)
  • 시뮬레이션 시스템을 리팩토링한 후 기존과 정확히 동일한 결과가 나오는지 확인하고자 할 경우. 특히 부동소수점 값의 정확성이 문제가 될 수 있다.

명백한 데이터

데이터의 의도를 어떻게 표현할 것인가? 테스트 자체에 예상되는 값과 실제 값을 포함하고 이 둘 사이의 관계를 드러내기 위해 노력하라. 테스트를 작성할 때는 컴퓨터뿐 아니라 후에 코드를 읽을 다른 사람들도 생각해야한다. 

명백한 데이터가 주는 또 다른 이점은 프로그래밍이 더 쉬워진다는 것이다. 단언 부분에 일단 수식을 써놓으면 다음으로 무엇을 해야 할지 쉽게 알게 된다.

명백한 데이터 코드에 매직넘버(인라인에 넣는 상수)를 쓰지 말라는 것에 대한 예외적인 규칙일 수도 있다. 이미 정의된 기호 상수가 있다면 그것을 사용할 것이라고 저자는 말한다.

 

Comments