SLASH 21 테스트 커버리지 100% 정리
테스트 코드를 왜 작성해야 되는지?
나는 테스트 코드를 쓰는 것에는 공감하고 있었지만, 실제로는 테스트 코드를 잘 쓰는 것과 왜 써야하는가에 대해서 항상 궁금해 했었는데, 이번 SLASH 21에 테스트 코드에 관련한 세션이 있어서 정리해보려한다.
실제로 이번 세션을 듣고 난 뒤에 테스트 코드에 관심이 많아졌으며 이 세션 이후로 테스트 코드를 작성하려고 많은 공부를 하게된 영상이라서 한번 정리하고 싶어서 작성된 글이다.
출처
내용 정리
테스트 커버리지 100%는 불가능할 것이라고 생각했지만, 18년도 11월 토스 홈 리뉴얼 프로젝트를 통해서 테스트 커버리지 100%를 달성할 수 있게끔 시도 해보았다.
시작한 무렵에는 50%였고 차후 84%가 될때 커버리지가 낮으면 배포가 안되는 설정을 통해서 실제로 테스트 코드를 더 많이 작성하고 더 효율적으로 작성하기 위해서 많은 노력을 했다.
이응준 강연자님이 말하는 높은 테스트 커버리지의 이점은 다음과 같았다.
- 배포의 자신감 → 모든 코드가 테스트 되어서 배포시 큰문제가 없을 거라는 안정감.
- 리펙토링에 대한 자신감 → 리펙토링자체에 문제가 있으면 테스트코드의 오류가 알려줄 것.
- 불필요한 프로덕션 코드의 삭제
- 프로덕션 코드에 대한 이해도 증가
- 높아지면 높아질수록 쉬워지는 테스트 작성 → 프로덕션 코드가 테스트를 작성하기 쉽게 변한다, 테스트 코드를 참고해 새 테스트 작성하기도 쉽다.
테스트 커버리지를 높이기 위해서 필요한 것들
믿음과 시간
테스트 커버리지를 높이기 위해서 필요하지 않은 것들
의지 → 의지는 Gradle Jacoco로 일정 테스트 커버리지가 넘지 않으면 빌드 되지 않도록 하면 된다.
테스트 커버리지를 높이면서 발생했던 어려움들
1. 테스트가 너무 느려진다.
테스트 코드가 증가하게 되고, 실행시간이 1분을 넘어가게 되었다. 테스트 코드를 실행하는 데 오랜 시간이 걸리면 생산성이 떨어지게되어서 해결해야만 했다.
느려지는 원인 → 스프링 애플리케이션 컨텍스트 로딩!
HTTP API 테스트를 할때 컨텍스트 로딩하는 경우가 많아서 자동적으로 테스트 코드 실행시간이 늘어남. 컨텍스트를 제거해주고 WebTestClient를 사용해서 컨텍스트 로딩없이 사용할 수 있게 대처
테스트케이스가 1600개쯤 넘어설때쯤 다시 1분이 넘어가게 되었고, 실제로 느려지게 되는 원인을 intellij의 프로파일링 기능을 활용해서, 느려지는 원인을 분석했고 여러가지 원인이 발생했다.
- SLF4J 초기화 → 불필요한 로깅 삭제
- Jackson ObjectMapper() 생성 → Jackson을 Gson으로 변경
- Handlebars 컴파일 → handlebars 캐시 적용
- Byte Buddy 초기화 → 테스트에서 사용중단
- 코틀린 리플렉션 모듈 초기화 → isSubclassOf 함수 호출 제거
- MockK → 필수적이지 않으면 모두 제거
- 테스트의 순차적인 실행 → 테스트 클래스 단위로 병렬 실행
초록색으로 색 치환되있는 것은 MockK가 Byte Buddy와 코틀린 리플랙션 모듈을 사용해서 동시에 느려졌다. 한개의 문제가 여러개의 문제를 동시에 발생하게 했다는 것을 강조하기 위해서 처리했다.
실제로 강연자님이 스스로 사용하던 노트북보다 맥북 프로가 훨씬 더 빠른 속도로 테스트코드를 처리할 수 있었기 때문에 돈을 좀 더써서 테스트 코드를 더 빠르게 변경시킬 수 있었다.
진짜 어려운 테스트 코드들
실제로 진짜 어려운 테스트 코드들은 "코틀린이 생성한 바이트 코드를 테스트하기" 가 제일 어려웠다.
왜 이렇게 까지 100%를 고집하는지?
100%는 단순한데, 새로 추가한 코드가 커버가 안되있으면 언제나 실패가 되고 그건 커버리지 리포트를 보면서 확인하면 된다.
99%는 복잡하다. 운 좋게 넘어갈 수도 있고 억울하게 실패할 수 있는 상황이 생긴다.
그래도 버그는 존재한다.
테스트 케이스가 부족한 경우 => 기능에 버그가 있어도 테스트 케이스가 적으면 틈이 존재할 수 있다. 그럼에도 불구하고 테스트 커버리지는 100%가 될 수 있다.
물론 이런 경우도 해결책이 있긴 있다. Mutating Testing 기법: 프로덕션 코드를 무작위로 조작해서 테스트가 통과하는지 실험하는 것.
JVM은 Pitest라는 솔루션이 있다.
주의점은 너무 느려서 가장 중요한 로직에 부분적인 적용을 하는 건 좋다. 전체 코드에 모두 적용하는 것은 너무 느리다.
개발자가 요구사항을 오해하는 경우 => 요구사항을 작성하는 사람과 구현하는 사람이 다른 사람이면 오해의 가능성이 크다. 물론 같은 사람이면 좋겠지만.. 실제로 그런 경우는 거의 없고 요구사항을 작성하는 사람이 테스트 자체를 작성하면 좋겠지만 그럴 일은 거의 없다.
이런 경우 테스트를 통해서 스펙문서를 만들어서 처리해봤다. Junit5의 TestExecutionListener를 통해서 스펙 문서를 만드는 방식으로 처리했다.
컴포넌트간 협업 실패
Consumer Driven Contracts 방식으로 처리.
결론
- 테스트 커버리지는 얼마든지 높일 수 있다
- 테스트 커버리지가 낮으면 빌드를 실패하게 하자
- 테스트는 빨라야한다.
- 커버리지는 100%라도 버그가 반드시 있다.
마지막으로...
개인적으로 테스트 코드에 대해서 고민이 많았었고, 도대체 뭘 해야하는건지를 그리고 왜 해야되는 것에 대해서 궁금했었는데, 이번 강연을 통해서 확실히 필요하다는 것을 알았다. 개인적으로 내가 테스트 코드를 작성해야겠다는 큰 계기가 된 동영상이라 같이 간단한 요약을 통해서 공유하고 싶어서 작성된 글이다.
모두 테스트 코드를 잘 작성해보자. 강연자님 너무 좋은 강연 잘 보았습니다! 😆
'잡담 > 관심 가는 기술들' 카테고리의 다른 글
if-kakao MongoDB 세션 정리 (0) | 2020.12.10 |
---|---|
요즘 이것저것 관심이 많다. (0) | 2019.10.03 |