UnitTest 프레임웍을 슬슬 바꿀 시점인가?

회사에서 C++로 작성하는 프로그램의 이런저런 유닛테스팅 용도로 UnitTest++을 사용해왔다. 굉장히 간결한 라이브러리이고 (header file 몇 개 + 라이브러리 하나), 전체 테스트 스윗이나 테스트 케이스 설정도 다음과 같은 형태라 무척 간단한다.

SUITE(SomeSuite) {
    TEST(Test1) {
        CHECK( … );
    }

    // ...
}

UnitTest++을 꽤나 편하게 쓰고 있었는데 굉장히 맘에 안드는 점이 몇 가지 있다.

테스트 케이스를 선별적으로 실행하기 힘들다 / 테스트 실행 인터페이스가 기본적으론 제공되지 않는다

기본적으로 제공되는 외부 인터페이스가 1갠데, 테스트를 실행하는 함수인 UnitTest::RunAllTest() 함수가 그 것이고 다음과 같은 인자를 받는다.

  • TestReporter : console 출력할지 특정 형태(XML이나 텍스트…)로 출력할지 결정함
  • Test-case들의 목록
  • 실행할 suite 이름
  • 실행할 test-case 이름

을 인자로 받고, 대부분의 경우 NULL이어도 된다. 

일부만 실행하려면 suite을 주거나 test-case 이름을 줘야하는데, 이러면 테스트가 전체적으로 잘 짜여있는 경우는 쉬운데 그렇지 않은 경우엔 참 뭣 같다. 게다가 저걸 커맨드라인이나 TestRunner 류에서 어떻게 전달할지도 따로 구현되어있질 않다.

내 경우엔 boost::program_options를 써서 *nix 스러운 커맨드라인 해석1 을 하게 했는데, 일단 짜서 유지해야하는게 좀 귀찮더라. 라이브러리 말고 딴걸 추가로 들고다녀야 된다는 점에서.

VisualUnitTest++ 이라고  VisualStudio 2005/2008과 통합되는 TestRunner가 있다는게 다행이지만, 커맨드라인 인터페이스가 없다는 점은 정말 감점 요인.

근데 최근에 다른 UnitTest 프레임웍을 살펴보다가 google test를 써보게 되었는데 이 녀석은 기본적으로 커맨드 라인 파서가 포함되어 있다. 게다가 환경변수로 지정하는 것도 가능해서 수고가 많이 줄어든다. 덤으로 미운놈은 뭘 해도 밉다고 UnitTest++의 XML 출력은 사람이 읽으란게 아니다(한줄로 나오냐 orz)

 

테스트 케이스의 흐름(control-flow)를 조절하기가 힘들다

테스트 케이스 쓸 때 불편한게, assert를 함부로 쓸 순 없으니(유닛 테스트 자체가 멈추니까), 검사는 하되 그 검사가 실패하면 해당 테스트 케이스 전체를 실패로 처리하는 기능이 자주 필요한데, 그런게 없다. 

UnitTest++에는 값 검사 매크로가 CHECK(), CHECK_EQUAL() 등등이 있는데, 값 검사가 실패(테스트 케이스가 잘못된)인 경우에도 무조건 실행된다. 이건 사실 당연한거지만, 특정한 경우 — 예를 들어 특정 파일을 여는데 이 파일이 없어서 그 이하의 테스트가 무의미한 경우 등등 — 에는 이게 좀 짜증난다. 테스트 케이스에서 내가 예외 처리도 하고 있어야 겠니? Orz

google test의 경우 값 검사 매크로가 ASSERT_* 계열과 EXPECT_* 계열로 나뉜다. ASSERT_* 류의 경우 해당 값 검사가 실패하면 그 테스트 케이스를 실패로 간주하고 다음 테스트 케이스로 넘어간다. EXPECT_* 류는 UnitTest++의 동작(실패하건 말건 다음 값 검사로 넘어감)과 같다.

즉, 어떤 파일을 연다고 치자. ASSERT_TRUE(some_fstream.good()); 을 쓴다면 파일을 못 열면 해당 테스트 케이스는 실패다. 그리고 그 테스트의 다른 검사는 실행되지 않는다. 반대로 EXPECT_TRUE(some_fstream.good()) 이라면 파일이 안 열려도 테스트는 속행하겠단 얘기다… UnitTest++ 에선 이런 실행 흐름의 조절이 불가능하고, 이는 일종의 스트레스 — 특히 저런 테스트 이후에 뭔가 실행되면 assertion-failure가 일어나는 경우 등등 — 로 다가올 뿐.

CruiseControl 과 통합하는 문제도 별 어려움이 없을듯하니, 이대로면 조만간 UnitTest++ 을 버리고 google test로 넘어가지 않을까 한다. 결정적으로 문서화의 질/양도 후자가 앞선다.2

ps. gtest는 페도라 등 주류 *nix 계열 OS에 팩키지로 제공되기도 하고, google mock framework이란 훌륭한 물건도 있다.


  1. --help 가 들어오면 help-message를, --ouput or -o 가 들어오면 파일 출력의 이름을 받게 했다. 비슷하게 --suite/-s 로 스윗 이름을, --testcase/-t로 테스트 케이스를 받는다. ↩︎

  2. UnitTest++이 매우 단순한 라이브러리인 탓도 있는데, 단 한 장의 문서로 모든걸 설명하고 있다. google test의 경우 기본문서/상세문서 두 가지가 꽤 자세한 설명/예와 합쳐져 있다. ↩︎