Unit Testing

이상 적인 단위테스트의 4대 요소

25G 2024. 2. 11. 11:58

잘 만들어진 단위테스트 스위트의 특성

  • 개발 주기에 포함돼 있다. 실제로 사용하는 테스트에만 가치가 있다. 그렇지않으면 작성해도 의미없다.
  • 코드베이스의 가장 중요한 부분만을 대상으로 한다. 모든 실행 코드에 똑같이 신경쓸 필요가 없다. 애플리케이션의 핵심을 다른것과 구별하는 것이 중요하다.
  • 최소한의 유지비로 최대 가치를 끌어낸다.
  • 가치있는 테스트와 낮은 가치의 테스트 식별
  • 가치 있는 테스트 작성

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

  • 회귀 방지
  • 리팩터링 내성
  • 빠른 피드백
  • 유지 보수성

회귀 방지

회귀는 소프트웨어 버그다.개발할 기능이 많을수록 릴리스가 될때마다. 고장날 가능성이 높아진다. 회귀 방지 지표에 대한 테스트 점수가 얼마나 잘 나오는지 평가하려면 다음을 고려하자

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

단순한 코드는 회기 될 확률도 없고 비즈니스 로직에 비해 가치가 낮을 확률이 높다. 외부라이브러리나 프레임워크등에 대한 의존성 테스트도 테스트 범주에 포함시켜서 소프트 웨어가 이러한 의존성에 대해 검증이 올바른지 확인한다. 회귀 방지 지표를 극대화하려면 테스트가 가능한 많은 코드를 실행하는것을 목표로 하는것이 좋다.

리팩터링 내성

이는 리팩터링 이후 테스트 케이스가 실패가 되지 않게 리팩터링을 할 수 있는지에 대한 척도이다. 이는 리팩터링 전후가 전부 기능이 정상작동을 하더라도 테스트 케이스가 실패할 수 있기때문이다. 이러한 상황을 거짓 양성 이라고 한다.
이를 평가하려면 테스트에서 얼마나 많이 거짓 양성이 발생하는지 살펴봐야한다. 적을수록 좋다.
왜 이부분이 중요하냐면 단위테스트를 작성하는 목적 자체가 지속적인 프로젝트의 성장이기때문.

  • 리팩터링의 스노우볼
    • 코드가 베포되기전에 조기 경고를 받을 수 있다.
    • 코드 변경이 버그로 이어지지 않을것이라는 확신을 얻을 수 있다. 이는 만약 테스트 스위트가 없었다면 리팩터링을 주저하게 됐을것 이로인해 코드는 계속해서 지저분 해 진다.

무엇이 거짓 양성의 원인일까?

테스트에서 발생하는 거짓 양성의 수는 테스트 구성 방식과 직접적인 관련이 있다. 테스트와 대상 시스템의 구현 세부 사항이 많이 결합할 수록 허위 경보가 더 많이 생긴다. 거짓 양성이 생길 가능성을 줄이는 방법은 해당 구현 세부 사항에서 테스트를 분리하는 방법 뿐이다.테스트는 최종 사용자의 관점에서 SUT를 검증해야 하고 최종 사용자에게 의미 있는 겨로가만 확인해야 한다. 다른 모든 것은 무시해야 한다.
SUT 알고리즘과 결함된 테스트. 이러한 테스트는 특정 구현을 예상하므로 깨지기 쉽다. SUT의 구현을 리팩터링하면 모두 테스트 실패로 이어진다. 리팩터링은 기능을 유지하며 코드를 수정하는것인데 테스트가 실패했다는 것은 바로 테스트가 구현 세부사항에 관련돼 있기 때문이다. 이렇게 작성하면 거짓양성이 발생할 가능성이 높아 지는 것이다.

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

리팩터링 내성을 높이는 방법은 세부사항과 테스트간의 결합도를 낮춰야한다.


위 첫번째 특성과 두번째 특성간에는 본질적인 관계가 있다. 둘다 정반대의 관점에서도 테스트 스위트의 정확도에 기여한다. 이 두 가지 특성은 시간이 흐르면서 프로젝트에 영향을 다르게 미치는 경향이 있다.

테스트 정확도의 극대화

  • 회기 방지와 리팩터링 내성 간의 관계는 회기 방지는 거짓음성을 피하는데에 도움을 준다. 반면 기능은 잘작동 하나 테스트는 실패하는 거짓양성을 잡기위해서는 리팩터링 내성을 높힐 필요가 있어진다.

빠른 피드벡

테스트 속도가 빠를수록 테스트 스위트에서 더 많은 테스트를 수행할 수 있고 더 자주 실행할 수 있다.

유지보수성

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

  • 테스트가 얼마나 이해하기 어려운가?
    • 테스트 코드의 품질은 제품코드만큼이나 중요하다.
  • 테스트가 얼마나 실행하기 어려운가?

이상적인 테스트는 뭐지?

이상적인 테스트는 위 네가지 특성을 고루 고려한 테스트가 될 수 있겠다. 정확하게 측정을 할 수는 없지만 추정치를 내어 네가지 방향성을 살필 필요는 있다. 테스트 코드를 포함한 모든 코드는 개발자의 책임이 된다.그렇기 때문에 임계치를 설정하고 이 임계치를 충족하는 테스트만 테스트 스위트에 남기는 것이 좋다.

그럼에도 이상적인 테스트는 만들 수 없다 왜냐하면 위 네가지 특성은 상호 배타적이기때문이다. 그렇지만 위 네가지 지표중 하나라도 0이되면 프로젝트에 좋지 않은 영향을 준다. 그렇기때문에 셋중 하나를 최대한 희생하여 나머지 둘을 최대로 하는 전략이 있다. 극단 적인 사례로는 엔드투 엔드 테스트가 있다. 이는 최종 사용자의 관점에서 다루기때문에 한번에 많은 코드를 테스트하므로 회귀 방지를 훌륭히 해낸다. 그리고 최종결과를 목표로 하는 테스트이기 때문에 거짓양성이 발생할 확률도 낮다. 하지만 엔드투엔드의 큰 단점은 "속도"이다. 이렇든 뼈를 주고 살을 취하는 전략이 필요하다.
대부분의 전략의 경우에 두개를 취하고 한개를 포기하는 전략을 사용하고 이들의 관계는 리팩터링 내성을 취하고 회귀방지와 빠른 피드백사이에서 선택을 하는데 테스트의 목적을 생각하면 회귀방지쪽에 좀더 힘을 실어주는게 좋지 않을까하는 생각이 든다.

 

출처: Unit Testing 블라디미르 코리코프