# 25장-테스트 주도 개발 패턴

어떻게 테스트 할 것인가?

* 테스트한다는 것은 무엇?
* 테스트는 언제하지?
* 테스트 로직은 어떻게 고르지?
* 테스트할 데이터는 어떻게 고르지?

## 테스트 - 명사

* 작성한 소프트웨어를 어떻게 테스트 할 것인가?
  * \=> 자동화된 테스트를 만들어라.
* test => 평가하다(동사)
  * '변화를 테스트할 수 있다' ≠ '테스트를 갖고 있다'
* test => `승인`이나 `거부`에 도달하는 과정
* '명사 테스트'와 '동사 테스트'는 다른 느낌을 줌 -> `왜그럴까`
  * 명사 테스트 = 자동으로 실행되는 과정
  * 동사 테스트 = 버튼을 눌러보고 화면의 결과를 주시

### Quality Software Management - 스타일 영향도 (influence diagram)

양성 피드백 고리 (positive feedback loop)

* 스트레스가 높아지면 테스트를 적게함
* 테스트 실행을 많이하면 스트레스가 적어짐

```
              - - - - - >
----> 스트레스                테스트 실행
              <- - - - -
```

스트레스를 많이 받으면 테스트를 뜸하게 하고, 테스트를 뜸하게 하면 에러는 많아지고, 에러가 많아지면 더 많은 스트레스를 받게되고...

{% hint style="info" %}
양성 피드백은 시스템의 출력이 입력량을 늘리는 방향으로 진행되는 피드백이다. 양성 피드백은 결과가 원인을 촉진하는 경우이고, 음성 피드백은 결과가 원인을 억제하는 경우이다.
{% endhint %}

이 고리를 빠져나오려면?

* 새로운 요소 도입
* 기존 요소와 바꿔치기
* 화살표를 바꾸기
* **현재의 경우** : `테스트`를 `자동화된 테스트`로 치환하면 됨

### 자동화된 테스트?

* 자동화된 테스트가 있다면, 스트레스를 받기 시작할 때 테스트를 실행할 것
* 테스트는 프로그래머를 위한 묘석 (두려움을 지루함으로 바꿔줌)
* 스트레스를 많이 받을수록 테스트도 더 많이 실행
  * 테스트 실행 -> 좋은 느낌 -> 작업중 에러 줄어듬 -> 스트레스 적어짐
  * 스트레스를 많이 받으면 결국 실패하는데, 자동화된 테스트가 있다면 두려운 정도를 선택할 수 있음

{% hint style="info" %}

{% endhint %}

* [ ] 트랜잭션을 시작하고 변수를 변경한 후에 트랜잭션이 가비지 컬렉트되도록 둔 경우에 롤백을 어떻게 구현할 것인가?
  * 트랜잭션 메커니즘이란 결국 트랜잭션이 커밋되기 전까지 변수가 진짜로 변하면 안된다는 것에 있다.
* [x] 자동화된 테스트에 대해 뭔가 더 설명할줄 알았는데 아쉬움;; 여기서 하고자 하는 말이 뭔지 헷갈림
  * 자동화된 테스트 : 테스트의 전 과정을 수동으로 하는 것이 아니라, IDE에서 하는 것처럼 코드를 짜고 버튼을 누르는 등의 행위

## 격리된 테스트

* 테스트를 실행하는 것은 서로 아무런 영향도 없는것이 좋다.

GUI테스트를 하면서 느낀 교훈

* 테스트는 충분히 빨라서, 내가 직접 자주 실행해야, 내가 만든 에러를 내가 먼저 잡을 수 있다.
* 어마어마한 양(의 에러)이 반드시 어마어마한 양의 문제를 의미하는 것은 아님 (앞의 테스트의 영향을 받는경우가 있음)

격리된 테스트

* 테스트가 실행순서에 독립적이게 된다는 점
* 테스트를 격리하기 위한 작업은 _결과적으로_ 시스템이 응집도는 높고, 결합도는 낮은 객체의 모음으로 구성되도록 하는것.

## 테스트 목록

뭘 테스트 해야하나?

* 시작하기전에 작성해야할 테스트 목록을 모두 적어둘 것
* 모든 것을 머릿속에 넣어두고 집중하면, 목표에서는 벗어나지 않지만, 양성피드백 고리에 빠짐
* 경험이 축절될수록 할일 목록이 많아짐 -> 목록이 많아지면 집중력이 떨어지고 성취도는 낮아짐 -> 성취도 낮아지면 할일목록 많아짐
* (실생활)`향후 몇시간` 내로 해치워야하는 할일 목록, 주단위, 월단위 목록을 만든다.
* TDD에서도 이것을 적용:
  1. **구현해야할 것들에 대한 테스트 목록을 적음**
  2. 존재하지 않는 오퍼레이션에 대해서는 널버전(아무일도 하지 않음)을 리스트에 적음
  3. 이 작업을 끝내기전에 반드시 해야할 리팩토링 목록을 적음
* 테스트 윤곽 뿐 아니라 테스트 전부 구현할 경우의 문제(?)
  1. 모든 테스트는 리팩토링에 대해 관성을 가짐... (209p 함께보아요) 고칠게 많아도, 이미 늦고 귀찮아서 안바뀐다는 말 같은데...
  2. 초록막대를 보는 것이 멀다, \~\~\~> 정신적 문제
* 신중한 등반가들의 규칙 : `등반할 때 두 다리와 두 팔 중 셋은 항상 고정한다`
  * 둘 이상을 동시에 움직임은 위험, TDD에서도 마찬가지
* 작성한 코드들은 새로운 테스트가 필요함을 암시적으로 알려줌, 이 새 테스트는 리팩토링과 마찬가지로 할일 목록에 적어두라.

## 테스트 우선

테스트를 언제 작성하는 것이 좋을까? 테스트 대상이 되는 코드를 작성하기 직전에 작성하는 것이 좋다.

코드를 작성한 후에는 테스트를 만들지 않을 것이다. 기능이 실행되도록 만드는 것이 목표.

양성피드백 고리를 벗어나자: 테스트를 먼저하면, 스트레스가 줄고 테스트를 더 많이하게 된다.

## Assert 우선

Assert는 언제쓸까? 제일 먼저 쓰고 시작하라!

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

## 테스트 데이터

테스트할 때 어떤 데이터를 사용해야하는가? 테스트를 읽을 때 쉽고 따라가기 좋을 만한 데이터를 사용하라. 테스트 작성에도 청중이 존재한다.

* 데이터 값을 산발하기 위해 산발하지 말 것.214 질문하나 (plus()메서드를 평가할 때 10384+1239123 보다는 1+2를 쓰라는 말이 맞나?)
* (대안으로는) 실제 세상에서 얻어진 실제 데이터를 사용하는 것

## 명백한 데이터

데이터의 의도를 어떻게 표현할 것인가? 테스트 자체에 예상되는 값과 실제 값을 포함하고 이 둘 사이의 관게를 드러내기 위해 노력하라.
