이 장에서 다룰 내용
•
왜 우리가 테스트를 싫어하는지와 왜 그것을 사랑하는지
•
테스트를 더 즐기는 방법
•
TDD, BDD와 같이 세 글자로 된 용어를 피하기
•
테스트 대상을 결정하기
•
테스트로 일을 줄이기
•
테스트가 내게 기쁨을 가져다주게 하기
•
개발자들이 테스트를 싫어하는 이유는 테스트가 제품과 분리된 것으로 보기 때문이다.
•
그러나 테스트는 개발자의 작업에 필수적이며 개발자에게 도움이 된다. 지금부터 자세히 알아보자.
1. 테스트의 유형
•
소프트웨어 테스트는 소프트웨어의 동작에 대한 자신감을 높이는 작업이다.
•
테스트의 유형을 분류하는 기준에는 여럿이 있지만 가장 널리 사용되는 기준은 테스트를 실행하거나 구현하는 방식이다.
◦
이는 테스트가 개발 시간에 많은 영향을 끼치기 때문이다.
1. 수동 테스트
•
개발자가 직접 코드를 실행하고 그 동작을 검사하여 테스트하는 방법이다.
•
코드 리뷰 역시, 효과가 약하긴 하나 테스트 방법 중의 하나로 간주된다.
2. 자동 테스트
•
테스트 역시, 우리를 위해 컴퓨터에게 실행해달라고 할 수 있다.
•
자동 테스트는 소프트웨어의 동작에 대한 신뢰도를 어느 정도까지 높이느냐에 따라 다르다.
•
단위, 통합 테스트 등이 속하며 단위에 대한 정의는 저마다 다르다.
3. 위험을 감수하라: 프로덕션 환경에서의 테스트
•
프로그래밍 세계에서 프로덕션 환경에서 테스트하는 것은 나쁜 행위에 속한다.
◦
오류에 화가난 고객이나 사용자가 떠나갈 수 있기 때문이다.
•
그러나 이 역시 항상 나쁘기만 한 것은 아니다. 테스트해야 할 시나리오가 자주 사용되는 중요한 코드 경로와 연관이 적다면 프로덕션에서 테스트해도 무리가 없을 수 있다.
◦
오류가 발생해도 사용자가 이 앱을 지속적으로 사용할 것이라고 생각한다면 이런 시나리오에서는 테스트를 수행해도 괜찮을 수 있다.
4. 적합한 테스트 방법 선택하기
•
테스트 방법을 결정하려면 각 방법이 가지는 비용과 위험을 잘 이해하고 있어야 한다.
◦
비용
▪
특정 테스트를 구현/실행하는 데 얼마나 많은 시간이 필요한가?
▪
몇 번 정도 반복해야 할까?
▪
테스트 코드를 변경하면 테스트할 줄 아는 사람이 있는가?
▪
이 테스트를 신뢰할 수 있게 유지하는 것이 얼마나 어려운가?
◦
위험
▪
이 시나리오가 깨질 가능성은 얼마나 될까?
▪
시나리오가 깨지면 사업에 얼마나 큰 영향을 줄까? 손해가 클까? 혹시 이걸 망치면 해고될까?
▪
시나리오가 깨지면 얼마나 많은 시나리오가 함께 깨지게 될까? 예를 들어 우편물 발송과 관련된 기능이 중지되면 이 기능에 의존하는 다른 여러 기능도 역시 깨질 것이다.
▪
이 코드는 얼마나 자주 변경될까? 앞으로는 얼마나 바뀔 것으로 예상하는가? 모든 변화는 새로운 위험을 가져온다.
•
두 요소를 고려하여 보다 우리 서비스에 적합한 테스트 방법을 선택해야 한다.
2. 걱정을 멈추고 테스트를 사랑하는 법
•
테스트 작성이 너무 어려울 것이라고 지레 겁먹지 말자. 테스트 프레임워크는 정말 잘 되어 있다.
•
테스트 프레임워크를 사용해 테스트를 작성하다보면 간편하고 빠른 피드백 덕분에 테스트를 작성하는 일이 신나게 될 것이다.
3. TDD와 같이 약어로 된 용어를 사용하지 마라
•
너무 특정 방법론에 매몰되어 본질을 놓칠 수 있다.
•
테스트는 매우 중요하나 우리는 제품을 개발하고 있으며 제품 코드가 먼저다.
•
테스트 때문에 고민해서는 안 된다. 테스트는 작성이 쉽고, 빠르게 끝나야 한다.
4. 자신의 이득을 위해 테스트를 작성하라
•
만들어둔 테스트는 나중에 보험처럼 동작한다.
•
테스트는 개발자가 깰 수 없는 코드와 명세 사이의 계약을 강요하며 이는 소프트웨어와 개발자 모두를 더 나아지게 한다.
•
효율적인 개발자가 되고 싶다면 테스트를 작성하자.
5. 테스트 대상 결정하기
•
테스트할 대상을 어떻게 찾아낼 수 있을까?
•
제품 코드를 무작위로 몇 줄 지우더라도 실패하게 되는 테스트를 어떻게 하면 작성할 수 있을까?
1. 경계를 존중하라
•
경계 조건에서부터 시작하라.
2. 코드 커버리지
•
너무 코드 커버리지를 맹신해서는 좋지 않다.
•
대신에 가능한 모든 입력을 고려하고 경계 값을 현명하게 처리하면서 테스트 적용 범위를 항상 의식하고 있어야 한다.
6. 테스트를 작성하지 마라
•
어떤 기능들은 테스트가 필요 없을까?
1. 테스트를 작성하지 마라
•
우리가 작성하지 않은 기능은 테스트를 작성할 필요가 없다.
•
가져다 쓴 패키지나 라이브러리의 기능이 정상적인 입력에도 오류를 내뱉는다면 Repository로 가서 Issue에 글을 남기면 된다.
2. 모든 테스트를 작성하려 애쓰지 마라
•
모두가 잘 알고 있는 파레토 법칙은 80%의 결과는 20%의 원인으로부터 기인한다고 말한다.
•
버그는 균일하게 발생하지 않는다. 보통 더 자주 사용되거나 변경되는 코드에서 버그가 발생할 가능성이 높다.
◦
이처럼 버그 발생 가능성이 높은 영역을 핫 패스라고 부른다.
•
웹 사이트의 홈페이지를 여는, 가장 기초적인 동작만으로도 연결된 기능들까지 테스트하므로 꽤나 괜찮은 범위를 커버한다.
◦
이를 거리에서는 스모크 테스트라고 부른단다. 컴퓨터의 최초 프로토타입을 개발했을 때, 연기가 나는지 안나는지 보기 위해 컴퓨터를 켰던 것에서 기인했단다.
•
마찬가지로 중요한 공유 의존성에 적절한 테스트 적용 범위를 갖게하는 것이 코드 커버리지 100%보다 더 중요하다.
7. 컴파일러가 코드를 테스트하도록 하라
1. 널 검사를 제거하라.
•
목적을 위해 특정 타입을 사용하면 테스트의 필요성이 줄어들 수 있다.
◦
함수가 문자열 대신 객체를 입력으로 할 때 함수에서는 해당 인수의 유효성을 검증하지 않아도 된다.
◦
컴파일러가 대신해줄 것이다.
2. 범위 점검을 제거하라
•
양수만 받는다면 굳이 타입이 int여야할 필요가 있을까?
◦
타입을 슬기롭게 사용하도록 하자.
3. 유효 값을 확인하는 로직에서 중복을 제거하라
•
너무 많은 책임을 가지는 함수를 분리한다면 테스트도 쉬워지고 작성해야할 테스트가 줄어들 수 있다.
•
효과적인 리팩토링을 통해 함수의 책임을 덜고 우리의 일도 덜어보자.
8. 테스트 이름 정하기
•
테스트는 다음 항목을 구분할 수 있어야 좋은 이름이다.
◦
테스트할 함수의 이름
◦
입력 및 초기 상태
◦
예상 동작
•
저자는 보통 다음 형식으로 테스트 이름을 짓는다.
9. 요약
•
애초에 테스트 작성을 많이 하지 않음으로써 테스트 작성에 대한 경멸을 극복할 수 있다.
•
테스트 주도 개발이나 그와 유사한 패러다임은 테스트 작성이 더욱 싫어지게 만들 수 있다. 내게 행복감을 주는 테스트를 작성하려고 노력하라.
•
특히 매개변수화된 데이터 기반 테스트와 함께 테스트 프레임워크를 이용하면 테스트 작성을 위한 수고를 크게 줄일 수 있다.
•
함수 입력의 경계 값을 잘 분석하면 테스트 수를 크게 줄일 수 있다.
•
데이터 타입을 적절하게 사용하면 불필요한 테스트를 많이 작성하지 않아도 된다.
•
테스트는 코드의 품질만을 보장하는 것이 아니라 여러분의 개발 기술과 처리량을 향상시키는 데도 도움을 줄 수 있다.