728x90

<단위 테스트 - 생산성과 품질을 위한 단위 테스트 원칙과 패턴>를 읽고 4장을 정리한 내용이다. 

 

가치 있는 테스트를 식별하는 것과

가치있는 테스트를 작성하는 것을 별개의 기술이다.

가치있는 테스트를 식별하는 방법을 이 장에서 알아볼 것이다.

4.1. 좋은 단위 테스트의 4대 요소

  • 회귀 방지
    • 테스트가 얼마나 버그를 잘 찾아 내는지
  • 리팩터링 내성
  • 빠른 피드백
    • 얼마나 빠른지
  • 유지 보수성

4.1.1 회귀 방지

코드는 자산이 아니라 책임이다.

코드베이스가 커질 수록 잠재적인 버그에 더 많이 노출된다.

회귀에 대해 효과적인 보호를 개발하는 것이 중요하다

회귀방지 지표에 대한 테스트 점수가 잘 나오는지 평가하기 위해 고려해야할 것

  • 테스트 중에 실행되는 코드 양
  • 코드 복잡도
  • 코드의 도메인 유의성

단순한 코드를 테스트하는 것은 가치가 없다. 버그를 잘 찾을 수 있는 것이 중요. 회귀 오류를 잘 찾는 것이 중요

회귀 방지 지표를 극대화 하려면 테스트가 가능한 많은 코드를 실행하는 것을 목표로 해야한다.

외부시스템에 의존하는 코드 즉 의존성에 대해 검증하는 코드도 중요하다

4.1.2 리팩터링 내성

리팩터링은 식별할 수 있는 동작을 수정하지 않고 기존 코드를 변경하는 것을 의미한다.

기존 코드를 변경하더라도 문제없이 코드가 동작해야한다.

기능은 문제가 없는데 기반 코드를 수정했을 때 테스트가 실패되었을 때의 결과를

거짓 양성이라 한다.

거짓양성은 허위정보이다.

리팩터링 내성 지표에서 테스트 점수가 잘 나오는지 평가하려면

거짓 양성 발생이 얼마나 적은지 보면 된다.

거짓 양성은

  • 타당한 실패도 무시하게 된다.
  • 테스트에 대한 신뢰도를 낮춘다.

4.1.3 거짓 양성의 원인이 무엇인가?

거짓 양성 수는 테스트 구성방식과 직접 관련이 있다.

테스트와 테스트 대상 시스템 sut의 구현 세부사항이 많이 결합할수록 허위 경보가 많이 생긴다.

구현 세부사항에서 테스트를 분리해야 거짓 양성을 줄일 수 있다.

테스트는 최종 사용자의 관점에서 sut를 검증해야하고

최종 사용자에게 의미있는 결과만 확인해야한다.

리팩터링 과정은 애플리케이션의 식별할 수 있는 동작에 영향을 주지 않으면서 구현을 변경하는 것인데

테스트를 구현에 결합하게 되면 구현을 리팩터링하면 모두 테스트 실패로 이어진다.

4.1.4 구현 세부사항 대신 최종결과를 목표로 하기

sut의 구현 세부사항과 테스트간의 결합도를 낮추는 것이 리팩토링 내성을 높이는 방법이다.

4.2 회귀방지와 리팩터링 내성 사이의 관계

둘다 테스트 스위트의 정확도에 기여한다.

프로젝트가 시작된 직후에는 회귀 방지를 잘 갖추는 것이 중요하지만

리팩터링 내성은 바로 필요하지 않다.

  • 테스트 정확도 극대화
  • 거짓양성과 거짓 음성의 중요성

4.2.1 테스트 정확도 극대화

테스트 통과, 기능 작동 : 올바른 추론 (참 음성)

테스트 통과 , 기능 고장 : 2종 오류(거짓음성)

테스트 실패, 기능 작동 : 1종 오류 (거짓 양성)

테스트 실패, 기능 고장 : 올바른 추론 (참 양성)

 

거짓 음성을 피하는데 좋은 테스트의 첫번째 특성인 회귀방지가 도움된다.

거짓 양성을 피하는데는 리팩터링 내성이 도움된다,

거짓양성과 거짓음성의 확률로 테스트 수준을 나타낼 수 있다. 즉 확률이 낮을 수록 테스트가 정확한다.

(아래 설명으로 이해함)

회귀 방지와 리팩터링 내성은 테스트 정확도에 기여한다.

테스트는 가능한 한 (리팩토링 내성 영역) 적은 소음(거짓양성) 으로 강한 신호(버그를 찾을 수 있음, 회귀 방지영역)을 발생시키기 때문에 정확하다.

정확한 지표는 다음 두가지 요소로 구성된다.

  • 테스트가 버그있음을 얼마나 잘 나타내는가 (거짓음성 제외 → 거짓음성이 적다는거겠지? )
  • 테스트가 버그 없음을 얼마나 잘 나타내는가. (거짓 양성 제외 → 적다는 거겠지? )

테스트 정확도 = 신호 (발견된 버그수) / 소음(허위 경보 발생 수)

4.2.2 거짓 양성과 거짓 음성 중요성: 역학 관계

둘다 나쁘지만

거짓 양성은 프로젝트가 커지면서 점점 더 큰 영향을 미치기 시작한다.

대부분 당장의 버그를 잘 잡는 회귀방지에만 중점을 두지만 프로젝트가 커지면서 거짓 양성에도 주의를 기울여야 한다.

4.3 세번째 요소와 네번째 요소 빠른 피드백과 유지 보수성

  • 빠른 피드백
    • 단위 테스트의 필수 속성
  • 유지 보수성

유지보수성 지표는 유지비를 평가한다.

  • 테스트가 얼마나 이해하기 어려운가. 테스트코드를 일급시민으로 취급하라
  • 테스트가 얼마나 실행하기 어려운가. 외부종속성으로 작동하면 그만큼 운영비가 든다.

4.4 이상적인 테스트를 찾아서

네 가지 특성을 모두 곱하면 테스트 가치가 결정된다.

즉 하나의 특성이 0이면 모두 0이다. 네 가지 범주에서 모두 점수를 내야한다.

테스트 코드를 포함한 모든 코드는 책임이다. 최소 필수값에 대해 상당히 높은 임계치를 설정하고 임계치를 충족한느 테스트만 테스트 스위트에 남겨라. 소수의 가치있는 테스트가 더 효과적이다.

4.4.1 이상적인 테스트를 만들 수 있나?

회귀방지, 리팩터링 내성, 빠른 피드백은 상호 배타적이다.

셋 중 하나를 희생해야 나머지 둘을 최대로 할 수 있다.

엔드 투 엔드 경우 최종 사용자의 관점에서 시스템을 살펴본다.

많은 코드를 테스트하여 회귀방지를 잘해낸다.

하지만 그만큼 속도가 느려 피드백을 빨리 받을 수 없다.

너무 간단한 테스트는 다양한 케이스를 검증할 수 없어 버그를 찾울 수 없기에 회귀를 나타내지 않는다.

깨지기 쉬운 테스트는 실행이 빠르고 회귀를 잡을 가능성이 높지만 거짓양성이 많은 테스트이다.

구현에 결합되어 있어 리팩터링 내성이 거의 없다

4.4.5 이상적인 테스트를 찾아서 결론

회귀방지, 리팩터링 내성, 빠른 피드백은 상호 배타적이다.

한가지특성을 희생해야한다.

네 번째 특성 유지보수성은 엔드투엔드 테스트를 제외하고 세가지 특성과 상관관계가 없다. (엔드투엔드는 모든 의존성을 설정하고 운영해야하므로 유지보수 비용이 많이 든다. )

그렇다면 어떤 특성을 희생해야하는가

리팩터링 내성은 포기할 수 없다. 최대한 많이 갖는 것을 목표로 해야한다.

결국 회귀방지와 빠른 피드백 사이에서 절충해야한다.

리팩터링 내성 포기할 수 없는 이유는 이진선택이기 때문에 있거나 없거나 둘 중 하나이다.

즉, 테스트 스위트를 탄탄하게 만들기 위해서는 테스트의 불안전성(거짓 양성)을 제거하는 것이 최우선 과제이다.

4.5. 대중적인 테스트 자동화 개념

테스트 피라미드는 테스트 스위트에서 테스트 유형간의 일정한 비율을 일컫는 개념이다

  • 엔드투 엔드 테스트
  • 통합테스트
  • 단위테스트

위에 있는 앤드투 앤드 테스트가 가장 사용자의 동작과 유사하게 흉내내고

아래에 있는 단위 테스트가 테스트 수가 가장 많다.

피라미드 내 테스트 유형에 따라 빠른 피드백과 회귀방지 사이에서 선택한다.

피라미드 상단의 테스트는 회귀방지에 유리 (여러 케이스로 버그 확인)

하단은 실행속도를 강조한다 (단위테스트는 빠른 피드백 강조)

통합테스트는 그 중간에 있다.

하지만 어느 계층도 리팩터링 내성을 포기하지 않는다!

테스트 유형간의 정확한 비율은 팀과 프로젝트마다 다르지만 일반적으로 피라미드 형태를 유지해야한다.

4.5.2 블랙박스 테스트vs 화이트박스 테스트간의 선택.

블랙박스테스트는 시스템 내부구조 몰라도 시스템의 기능을 검사할 수 있는 테스트 방법이다.

어떻게가 아닌 무엇을 해야하는지가 중심

화이트박스 테스트는 내부를 검증하는 테스트 방식이다

소스코드에서 파생

결론적으로 모든 테스트가 시스템을 블랙박스로 보게 만들고 문제영역에 의미있는 동작을 확인해야한다.

테스트를 분석할 때는 화이트 박스, (코드 커버리지 도구를 사용해서 어떤 코드분기를 실행하지 않았는지 확인)하고

코드 내부 구조에 대해 전혀 모르는 것처럼(블랙박스)로 테스트하라

이런 조합이 가장 효과적이다

728x90

+ Recent posts