Search
📖

좋은 테스트에 대한 고민

  좋은 테스트란?

1. 실행 속도가 빨라야 한다.

빠른 피드백은 개발 속도를 향상시켜준다.
너무 느리면 테스트를 자주 실행하지 않게 된다.

2. 내부 구현 변경 시 실패하지 않아야 한다.

리팩토링할 때 테스트가 깨진다면? -> 오히려 코드 개선을 방해
자주 변하는 로직과 변하지 않는 로직을 구분

3. 버그를 검출할 수 있어야 한다.

소스 코드에 버그가 있어도 검출하지 못한다면 잘못된 테스트
테스트가 기대하는 결과를 구체적으로 명시하지 않으면 버그를 검출할 수 없음

4. 테스트의 결과가 안정적이어야 한다.

특정 환경에서만 실패하거나, 실행할때마다 결과가 달라지는 테스트는 신뢰할 수가 없음
외부 환경의 영향을 최소화해서 동일한 결과를 최대한 보장할 수 있는게 중요함

5. 의도가 명확히 드러나야 한다.

가독성 : "기계가 읽기 좋은 코드" ⇒ "사람이 읽기 좋은 코드"
테스트 코드를 보고 한 눈에 어떤 내용을 테스트하는지를 파악할 수 있어야 함.

  테스팅 ROI (투자 수익률)

테스트 코드 작성과 유지보수는 비용이다

테스트가 없는 것보다는 있는 게 무조건 낫다?
테스트는 많을 수록 좋다?
불필요한 테스트나 잘못 짜여진 테스트는 차라리 없는게 나음

비용 대비 효과가 충분한가?

테스트를 작성하는 비용에 비해 얻을 수 있는 효과가 더 큰가가 중요
로직이 거의 없는(trivial) 코드는 따로 테스트하지 않아도 됨
동어 반복적인 테스트를 피하자
테스트 범위에 대한 조절이 필요 (단위 테스트 vs 통합 테스트 vs E2E 테스트)
모든 모듈에 대해 단위 테스트를 작성하는 것은 비효율적
모든 테스트 케이스를 E2E 테스트로만 검증하는 것도 비효율적

커버리지 100%를 목표로 하는 것은 비효율적

라이브러리 등은 100% 커버리지 가능
복잡한 어플리케이션의 경우 적절한 선을 잘 찾는 것이 중요

테스팅 도구와 테스팅 방법론은 아직 성숙한 상태가 아님

특정 방법론이나 도구에 집착하지 말 것
발전하는 테스팅 도구들을 눈여겨 볼 필요도 있음

커버리지 100%?

Kent Beck - Test Desderata

1) Isolated

tests should return the same results regardless of the order in which they are run.

2) Composable

if tests are isolated, then I can run 1 or 10 or 100 or 1,000,000 and get the same results.

3) Fast

tests should run quickly.

4) Inspiring

passing the tests should inspire confidence

5) Writable

tests should be cheap to write relative to the cost of the code being tested.

6) Readable

tests should be comprehensible for reader, invoking the motivation for writing this particular test.

7) Behavioral

tests should be sensitive to changes in the behavior of the code under test. If the behavior changes, the test result should change.

8) Structure-insensitive

tests should not change their result if the structure of the code changes.

9) Automated

tests should run without human intervention.

10) Specific

if a test fails, the cause of the failure should be obvious.

11) Deterministic

if nothing changes, the test result shouldn’t change.

12) Predictive

if the tests all pass, then the code under test should be suitable for production.

Kent Beck - “I get paid for code that works, not for tests”

I get paid for code that works, not for tests, so my philosophy is to test as little as possible to reach a given level of confidence (I suspect this level of confidence is high compared to industry standards, but that could just be hubris). If I don’t typically make a kind of mistake (like setting the wrong variables in a constructor), I don’t test for it. I do tend to make sense of test errors, so I’m extra careful when I have logic with complicated conditionals. When coding on a team, I modify my strategy to carefully test code that we, collectively, tend to get wrong.
Different people will have different testing strategies based on this philosophy, but that seems reasonable to me given the immature state of understanding of how tests can best fit into the inner loop of coding. Ten or twenty years from now we’ll likely have a more universal theory of which tests to write, which tests not to write, and how to tell the difference. In the meantime, experimentation seems in order.

Kent Beck - Extreme Programming Explained

It is impossible to test absolutely everything, without the tests being as complicated and error-prone as the code. It is suicide to test nothing (in this sense of isolated, automatic tests). So, of all the things you can imagine testing, what should you test?
You should test things that might break. If code is so simple that it can't possibly break, and you measure that the code in question doesn't actually break in practice, then you shouldn't write a test for it...
Testing is a bet. The bet pays off when your expectations are violated [when a test that you expect to pass fails, or when a test that you expect to fail passes]... So, if you could, you would only write those tests that pay off. Since you can't know which tests would pay off (if you did, then you would already know and you wouldn't be learning anything), you write tests that might pay off. As you test, you reflect on which kinds of tests tend to pay off and which don't, and you write more of the ones that do pay off, and fewer of the ones that don't.

테스팅 전략의 중요성

좋은 테스트의 요소 중 여러 개를 동시에 만족하기는 어려움 (서로 상충됨)
예) 테스트 단위가 작으면
장점: 실행속도가 빠르고 엣지 케이스 검증이 쉬움
단점: 작은 단위의 변화에도 깨짐, 모의 객체 사용이 늘어 버그 검출이 어려워짐
프로젝트의 특성에 따라 더 중요한 가치를 판단해서 전략을 세워야 함
테스팅 ROI를 고려해서 가장 효율적인 전략을 세우는 것이 필요