프로그램을 작성함에 있어 테스트케이스의 중요성은 대부분의 프로그래머가 공감하고 있는 듯 하다. 하지만 테스트케이스를 어떻게 작성하는것이 적당한지에 대해서는 프로그래머 개개인의 철학이나 경험(또는 삽질)한 정도에 따라 다른 생각을 갖고 있는 것 같다.
개인적인 생각으로는 이상적인 테스트케이스는 다음을 만족하면 된다.
- 모든 코드를 커버하고 있음 ( Quantity )
- 현재 코드의 정상, 예외 경우에 적절히 동작함을 검증함 ( Quality )
- 미래의 코드 변화에도 적절히 대응할 수 있는 구조로 되어 있음 ( Well-structured )
이번 글에서 소개하고자 하는 Mutating Testing은 위에서 제시한 이상적인 테스트 케이스의 2번을 만족시키기 위한 방법중 하나로, 테스트케이스 자체를 검증하는 방법이다.
Mutation 이란?
Mutating Testing에서 Mutation은 소스코드에 하나의 작은 변화를 발생시킨 것을 말한다. 즉, 아래와 같은 코드 변화를 주는 것을 의미한다.
// Original Source Code if ( amount > THRESHOLD ) { // Do Something } // Mutation if(amount >= THRESHOLD) { // Do Something }
Mutation Testing
위와 같이 생성한 mutations를 기존 테스트코드로 테스트 하는 것을 Mutation Testing이라고 한다. 이 결과는 다음의 두가지 경우로 나뉠 것이다.
테스트 실패 ( 긍정적 )
mutation에 대해 테스트 코드 수형 결과가 실패이다.(Mutation Testing에서는 Test Killed라고 표현한다.) 이 경우 기존에 작성한 테스트케이스가 적절한 테스트 케이스였음을 의미한다.
테스트 성공 ( 부정적 )
mutation에 대해 테스트 코드 수행 결과가 성공이다.(Mutation Testing에서는 Test Servived라고 표현한다.) 이 경우 기존에 작성한 테스트케이스는 로직 변경을 감지하지 못하고 성공 응답을 주었으므로 적절하지 않은 테스트케이스였음을 의미한다.
생성한 모든 mutants에 대해 테스트가 실패하였다면 테스트케이스가 로직의 변화에 민감하게( 알맞게 ) 짜여져 있는 것이므로 테스트케이스의 Quality가 적절함을 검증했다고 볼 수 있다.
Mutation Testing in Real World
이 방법론에 대해서는 이미 1980년대에 소개되었다.(T. Acree, T. A. Budd, R. A. DeMillo, R. J. Lipton, and F. G. Sayward, "Mutation Analysis," Georgia Institute of Technology, Atlanta, Georgia, Technique Report GIT-ICS-79/08, 1979.) 하지만 코드의 작은 부분 하나하나를 바꾸어 가며 테스트를 수행하면 엄청난 수의 조합이 발생하기에 이를 수행하기에는 너무 오래 걸려서 실무에서 사용되기는 어려웠다고 한다. (밤새 테스트케이스를 돌리고 다음날 확인하는 경우도 있었다고 한다.)
하지만 요즘 컴퓨터의 수행 속도라면 어느정도 "돌릴 만한" 수준까지 올라왔다고 판단되어 다시 주목받고 있다. 최근의 나온 framework 중에서는 code coverage를 이용하여 mutation이 영향을 받는 부분의 테스트 케이스만을 수행하게 하여 속도를 더 향상시킨 경우도 있다고 한다.(PIT)
Java 환경에서 mutant를 생성하고 테스트를 돌리는 framework로는 PIT(http://www.pitest.org), Jumble(http://jumble.sourceforge.net/), Jester(http://jester.sourceforge.net/) 등등 여러 framework가 있다.
새로 시작하거나 간단히 만들어 볼 프로젝트가 있다면 code coverage와 함께 mutation testing을 적용하여 테스트 코드의 품질을 올려보는것도 좋을 것 같다.
본 포스팅은 아래의 글을 참조했습니다.