Unit Test 와 테스트 케이스 작성, 코드 커버리지…

 

1. Unit Test

막연히 Unit Test를 작성해야 한다고 들었다. 버그를 줄여주고, 그리고 TDD 와의 연계…

(ps. 의외로 Unit Test 와 TDD 를 하나라고 보는 시각이 많은데, 나는 Unit Test 와 TDD 는

  조금 다르다고 생각한다. TDD는 실패하는 테스트 케이스를 만들어서, 이를 성공시켜 가면서

개발을 하는것이고, 즉, TDD 안에 Unit Test라는 과정이 포함되어 있는것이고, Unit Test 는

그냥 단순히 모듈에 대해서 테스트를 작성할 수도 있다. Unit Test의 강점은 “회귀 테스트” 가

아닐까 생각한다.)

그런데, Unit Test 를 작성해라. 라는 말은 듣지만, 실제로 어떻게 작성하면 잘 작성하는 것인가?

라는 의문이 생기게 된다.

 

2. 코드 커버리지

다른 말로 테스트 커버리지 라고도 한다. 팀마다 Statement Coverage, Branch(Decision) Coverage, Condition Coverage, Modified Decision/Condition Coverage 등을 측정하는데

사실 가장 좋은것은 Modified Decision/Condition Coverage 를 측정하는 것이고, 보통의

툴들은 Branch Coverage 를 측정해 준다. 실제 코드 커버리지를 측정하면, 코드의 어느 범위

까지 어떤 경우까지 테스트가 되었는지 알 수 있다.

 

3. 테스트 케이스 작성

여기서 말하는 테스트 케이스는 QA에서 하게 되는 인수테스트를 말하는 것이 아니라, 개발자의

Unit Test를 말한다. 자, 그럼 이제부터 Unit Test를 어떻게 작성해야 하는가? 바로 위의

Modified Decision/Condition Coverage 나 Branch Coverage 를 모두 측정할 수 있는

형태로 Unit Test 를 작성하면 된다. (말은 퍽 쉽다!!!)

 

즉, 하나의 모듈에서, 입력과 조건에 따라서 수행될 수 있는 케이스에 대해서 체크를 하고

이에 맞게 Unit Test를 만들면, 잘 만들었다고 할 수 있는 것이다. 그럼 이런 입력 조건에

대해서 테스트 케이스를 만드는 건 어떻게 할 수 있을까?

그래서 개발자가 테스트에 대해서 잘 아는 것도 중요해 질듯 싶다. 나도 잘 몰라서 공부중이다.

GoogleTest 에서의 Setup 과 TearDown 의 호출과정

 지금까지 난 TestSuite 에서 TestCase 가 호출되면 SetUp 과 TearDown 은 딱 한번만 불리는 줄 알았더니

TestCase 수 만큼 불리는 것이었다 -_- T.T 결국 그것 때문에 Google Test의 소스까지 쭈욱 까보는 삽질을

(사실, 이 소스 까보기는 딴 버그를 확인하기 위해서 해본것이었다.)

 

 덕분에 안것 몇가지는 구글 테스트는 Template 을 내부적으로 잘 사용했다.

윈도우 계열에서는 테스트 안전성을 위해서 SEH를 사용하고 있다.

 

 흑흑흑, 까보면 의외로 복잡해 보이지만, 쉽게 따라가진다. -_-

 그리고 몰랐던게, WinCE 계열을 공식적으로 지원한다는 것 -_-

 

흐음… google test 에 버그레포팅을 했는데 패치까지 제공하는게 좋을까 고민이다. 

Google Test에서 SetUp, TearDown 사용하기

 보통 UnitTest Framework 에서 공통적으로 선처리, 후처리 해야 할 항목들을 처리하기 위해서

TearUp SetUp, TearDown 이라는 메서드를 제공한다. 이것들은 첫 테스트가 시작되기 전에 동작하고, 또 마지막

테스트가 끝난 후에 동작하게 된다.

 

 google test 에서는 SetUp, SetDown TearDown 이라는 형태의 가상함수로 제공하고 다음과 같이 사용한다.

 

class TestClass : public testing::test

{

 protected:

        void SetUp();

        void SetDown();

 void TearDown();

};

 

위의 함수를 오버로딩해서

 

TEST( TestClass, test1 )

TEST_F(TestClass, test1)

{

}

 

형태로 처리하면 SetUp 이 먼저 호출되는 것을 알 수 있게된다.

 

ps. 무식이 탄로났다. SetUp, SetDown, TearUp, TearDown 을 혼용해서 쓰는게 아니라

SetUp, TearDown 이다. -_- 우어어어, 미리 확인못하고 올려서 죄송 T.T 

google test 결과를 XML로 보기

  google test 에서 결과를 XML로 출력하는 방법은 다음과 같다.

 

실행시에 –gtest_output=xml 라고 추가하면 된다.

 

그럼 결과는 다음과 같이 나온다.

 

 

<?xml version=”1.0″ encoding=”UTF-8″ ?>

<testsuite tests=”1 failures=”0 disabled=”0 errors=”0 time=”0 name=”AllTests“>

<testsuite name=”GTEST_TEST tests=”1 failures=”0 disabled=”0 errors=”0 time=”0“>

<testcase name=”test1 status=”run time=”0 classname=”GTEST_TEST” />

</testsuite>

 </testsuite>

 

 

나의 첫 번째 TDD – 결과

  회사에서 해야하는 프로젝트에 TDD를 적용해 보겠다고 생각을 했었다.

 

보통 TDD의 단계는 다음과 같다.

  1. 실패하는 테스트를 작성한다.
  2. 실패하는 테스트를 간단하게 성공하게 만든다.
  3. 다시 실패하는 테스트를 작성한다.(1번 보다 더 테스트를 할 수 있는…)
  4. 다시 실패하는 테스트를 성공하게 만든다.

 

위의 단계를 기본적인 함수군을 테스트 하는데는 유효했다.

그런데 캡슐화된(? 정말일까?) 클래스를 테스트 하면서 부터, 인터페이스를 public 으로 고치든지

새로운 클래스로 상속받아 임시로 protected: 를 public 으로 수정한 함수를 제공한다든지의 방법을

사용하게되었는데 -_-;

 

 이러면서 테스트가 조금씩 문제가 발생하기 시작했다. -_-

 

 그리고 뒤의 테스트를 추가하기 위해서 인터페이스가 바뀌면 이전의 테스트를 수정해야 하는 문제도

발생했다.

 

 그리고 결정적으로, 어떤 식으로 클래스의 동작을 제대로 체크할 것인가가 문제가 되었다.

 

내가 작성하는 프로그램은, 네트웍, GUI를 모두 사용하는 데, 이에 대해서 Mock을 사용할 것인지 아니면

실제로 테스트를 붙일것인지도 문제가 되었다.

 

 단순 UI와의 통신이 아니라, 나의 클래스는 UI 생성을 내부적으로 해야하는 기능도 있었기 때문에, 제대로

UI가 나타났는지도 테스트를 해야만 했다. -_-

 

 결국 일정이 급해지고, 이것 저것 수정하면 TDD는 잠시 무너진 T.T 그러나 단순 함수들에서도 실수가 많았는데 TDD를 이용하면서 단순 함수군에 대해서는 꽤 좋은 효과를 볼 수 있었다.

 

 이번 실패의 큰 원인은,

  1. 테스트를 어떻게 할 것인지, 제대로 생각하지 못했다.

    1. 이게 제일 크다.
  2.  네트웍, GUI 등에 대해서 테스트를 할 수 있는 인터페이스를 제대로 뽑지 못했다.

    1. 즉, 기존 설계가 좀 잘못되었다. -_-

 

 이번 경험을 삼아서 좀 더 제대로 설계를 하고, 제대로 TDD를 전개해 봐야겠다.

 

 TDD 프레임웍은 구글 테스트를 이용했다. 환경은 Window Mobile 6.1 

Google Test

 최근 들어서 자꾸 UnitTest 와 Regression Test 의 중요성이 커지고 있다. 이번 프로젝트에 UnitTest 를 도입하고자 했었지만, 사실 제대로 도입하지 못했다. 커버 범위가 거의 0.1% 수준 T.T

 

 그런데 결국 중간 중간 문제가 터졌다. 자동화된 Regression Test 만 있더라도 어느 부분이 커버가 가능했을 텐데, 요새 각광 받고 있는 것이 UnitTest++ 과 Google 에서 만든 Google Test 인 것 같다. Google Test 에서 Google Test 를 테스트 하는 코드를 보면, 그 커버 범위가 장난이 아니다.

 

 여기서 잠깐!!!

 

  • UnitTest(단위 테스트)

    • 하나 하나의 모듈이 올바로 동작하는 지 검증하는 것.
    •  보통 프로그래머가 수행
  • Regression Test

    • 변경 후에 변경이 타 부분에 영향을 미치지 않았는가를 테스트 하는 것
    • UnitTest 로 Regression Test 를 수행할 수 도 있다.

 

 결국 Google Test 를 좀 봐 주는 것이 좋을듯 해서 잠시 찾아봤다. 다음 블로그에 사용법이 자세히 나와있다. 설치는 VC++의 경우 Solution 이 gcc 계통에는 Makefile 이 제공되니 쉽게 이해할 수 있을듯 하다.

 

http://decoder.tistory.com/559