TDD로 구현하면서 객체를 추출하는 리팩토링(extract class)을 하는 경우가 종종 발생한다. 이와 같이 extract class 리팩토링을 진행할 때 새로 추출한 클래스에 대한 단위 테스트를 추가하는 것이 좋을까? 어떤 기준으로 테스트 유무를 판단하는 것이 좋을까?
이번 재직자 교육 과정을 진행하면서 관련 질문을 받았는데 나 또한 명확한 기준 없이 구현했다는 느낌이 든다.
TDD as if you Meant It: Refactor to a new Class 글에서는 다음과 같은 기준으로 테스트 코드 구현 유무에 대한 가이드를 제공하고 있다.
The extracted class needs to either have only logic, or only to hold data. Whenever I don’t have any logic in the extracted class, I won’t add new tests. If the extracted class has logic, but it is trivial, I will use the existing indirect tests. If the extracted class has a lot of logic, I will split the existing tests to have specific tests for the extracted class, and smaller (simpler) initial tests.
추출한 클래스가 단순히 데이터를 저장하는 용도냐 로직을 처리하느냐에 따라 구분하고 있다.
- 로직이 없는 경우 새로운 테스트를 구현하지 않는다.
- 추출한 클래스가 로직을 가지지만 그리 중요하지 않은 로직(trivial)이라면 리팩토링 전에 구현한 테스트를 통해 간접 테스트가 가능하도록 한다.
- 추출한 클래스가 많은 로직을 구현하는 경우 새로운 테스트 코드를 추가한다.
추출한 클래스에 대해 새로운 테스트 코드를 추가하는 경우 구현 순서는 다음과 같겠다.
- TDD로 기능 구현.
- 리팩토링 중 extract class 리팩토링을 통해 새로운 클래스 추가. 이 시점에 새로운 테스트 추가 없음
- 새로 추가한 클래스에 대한 테스트 코드 추가
- 최초 TDD로 구현한 테스트에서 중복되는 테스트 제거
그 동안 딱히 의식하지 않고 구현했는데 위 가이드를 기준으로 구현해 봐도 좋겠다.
1개의 의견 from FB
2개의 의견 from SLiPP
위 규칙에 동의하는 편입니다.
테스트 코드를 작성하는 이유중의 하나는 테스트 코드만 읽고 이해해도 제품 코드를 이해할 수 있게 하는 것이라고 생각합니다. 즉 테스트 코드는 제품 코드의 동작을 명세하는 문서가 되어야 하는 것이죠. 개발자가 코드를 변경하거나 새로운 기능을 추가할 때 기존 동작을 쉽게 파악하는데 테스트 코드가 도움이 되어야 겠죠.
이런 기준으로 생각해보면
새로 추출된 클래스에 로직이 없다면, 클래스이름 메소드 이름만으로도 클래스의 동작을 바로 이해할 수 있겠죠. 그래서 테스트가 필요없습니다.
새로 추출된 클래스의 로직이 간단하다면, 동작을 이해하기 위해서 코드를 조금 살펴보긴 해야 하지만 코드를 읽고 이해하는 것이 어렵지 않을 것이기 때문에 개발자의 시간을 많이 빼앗진 않을 것이라고 봅니다. 별도 문서(테스트 케이스)가 없어도 그 클래스가 어떤 일을 하는지 알 수 있는 경우이겠죠.
새로 추출된 클래스의 로직이 복잡하다면, 코드의 동작을 이해하기 위해서는 추출되기전에 작성된 테스트 케이스를 읽고 동작을 추론해야 합니다. 이전 클래스의 테스트 케이스에는 새로 추출된 클래스뿐만 아니라 다른 부분의 로직도 섞여 있을 것이기 때문에 새로 추출된 클래스의 동작을 이해하려면 시간을 조금 더 소비해야 하겠죠. 새로 추출된 클래스에 테스트 코드가 잘 작성되어 있다면 테스트 케이스를 읽기만 해도 해당 클래스의 동작을 쉽게 파악할 수 있을 거라고 생각합니다. 새로 추출된 클래스에 테스트 코드가 추가되고 나면 기존 클래스의 테스트 코드는 통합 테스트가 되기 때문에 통합 테스트 관점에서 불필요한 테스트 코드를 제거합니다. 기존 테스트 코드를 제거하는 이유는 동일한 상황을 테스트하는 테스트 케이스가 중복이기 때문입니다(DRY 원칙). 기존 테스트 코드를 제거하지 않으면 나중에 새로 추출된 클래스의 요구사항이 변경될 때 두 개의 테스트 케이스(클래스 추출 이전의 테스트 케이스, 새로 추출된 클래스의 테스트 케이스)가 깨지게 됩니다. 이런 상황이 발생하면 코드를 수정한 개발자는 당황하게 될 것이고 추출되기 전 클래스의 테스트 케이스가 왜 깨지는지 살펴보고 테스트 케이스를 수정해야 합니다. 코드를 수정하는 개발자의 시간을 빼앗게 되는 것이죠.
의견을 남기기 위해서는 SLiPP 계정이 필요합니다.
안심하세요! 회원가입/로그인 후에도 작성하시던 내용은 안전하게 보존됩니다.
SLiPP 계정으로 로그인하세요.
또는, SNS 계정으로 로그인하세요.