출처 : IBM.com
유닛 테스트를 위한 오픈 소스 도구에 대한 시리즈에서 두 번째인 이 기사에서는 매우 유명한 CppUnit(Eric Gamma와 Kent Beck이 처음 개발한 JUnit 테스트 프레임워크의 C++
포트)에 대해 소개한다. C++
포트는 Michael Feathers에 의해 만들어졌으며 화이트 박스 테스트와 사용자 고유의 회귀 스위트 작성을 지원하는 다양한 클래스를 구성한다. 이 기사에서는 TestCase, TestSuite, TestFixture, TestRunner 및 헬퍼 매크로와 같이 더 유용한 CppUnit 기능 중 일부에 대해 소개한다.
이 기사의 목적상 CppUnit을 다운로드하여 g++-3.2.3 및 make-3.79.1이 설치된 Linux® 시스템(커널 2.4.21)에 설치했다. 설치는 간단하며 표준 설치이다. configure
명령을 실행한 후 make
및 make install
을 실행한다. Cygwin과 같은 특정 플랫폼의 경우에는 이 프로세스가 원활하게 실행되지 않을 수 있기 때문에 설치와 함께 제공되는 INSTALL-unix 문서에서 세부 사항을 확인해야 한다. 설치가 완료되면 설치 경로에 CppUnit을 위한 include 및 lib 폴더가 표시된다(해당 경로를 CPPUNIT_HOME이라고 함). Listing 1에 파일 구조가 표시된다.
Listing 1. CppUnit 설치 계층 구조
[arpan@tintin] echo $CPPUNIT_HOME /home/arpan/ibm/cppUnit [arpan@tintin] ls $CPPUNIT_HOME bin include lib man share |
CppUnit을 사용하는 테스트를 컴파일하려면 소스를 빌드해야 한다.
g++ <C/C++ file> -I$CPPUNIT_HOME/include –L$CPPUNIT_HOME/lib -lcppunit |
CppUnit의 공유 라이브러리 버전을 사용하는 경우 소스를 컴파일하려면 –ldl
옵션을 사용해야 할 수 있다. 설치 후 libcppunit.so의 위치를 반영하려면 UNIX® 환경 변수 LD_LIBRARY_PATH를 수정해야 할 수도 있다.
CppUnit에 대해 살펴보는 데 가장 적절한 방법은 리프 레벨 테스트를 작성하는 것이다. CppUnit은 테스트 설계 중에 활용할 사전 정의된 클래스의 전체 호스트와 함께 제공된다. 연속성을 위해 이 시리즈의 part 1에서 설명한 설계가 부실한 문자열 클래스를 떠올려 보자(Listing 2 참조).
Listing 2. 창의적이지 않은 문자열 클래스
#ifndef _MYSTRING #define _MYSTRING class mystring { char* buffer; int length; public: void setbuffer(char* s) { buffer = s; length = strlen(s); } char& operator[ ] (const int index) { return buffer[index]; } int size( ) { return length; } }; #endif |
일반적인 문자열 관련 검사에는 비어 있는 문자열의 크기가 0인지 확인하는 것과 오류 메시지/예외에 있는 문자열 결과에서 색인을 벗어나서 액세스하는 것 등이 포함된다. Listing 3에서는 이러한 테스트에 CppUnit을 사용한다.
Listing 3. 문자열 클래스에 대한 유닛 테스트
#include <cppunit/TestCase.h> #include <cppunit/ui/text/TextTestRunner.h> class mystringTest : public CppUnit::TestCase { public: void runTest() { mystring s; CPPUNIT_ASSERT_MESSAGE("String Length Non-Zero", s.size() != 0); } }; int main () { mystringTest test; CppUnit::TextTestRunner runner; runner.addTest(&test); runner.run(); return 0; } |
살펴볼 CppUnit 코드 베이스의 첫 번째 클래스는 TestCase
이다. 문자열 클래스에 대한 유닛 테스트를 작성하려면 CppUnit::TestCase
클래스를 서브클래스화하고 runTest
메소드를 대체해야 한다. 테스트가 정의되었으므로 개별 테스트를 추가해야 하는 제어기의 일종인 TextTestRunner
클래스를 인스턴스화한다(vide addTest
메소드). Listing 4에는 run
메소드의 출력이 표시된다.
Listing 4. Listing 3의 코드 출력
[arpan@tintin] ./a.out !!!FAILURES!!! Test Results: Run: 1 Failures: 1 Errors: 0 1) test: (F) line: 26 try.cc assertion failed - Expression: s.size() == 0 - String Length Non-Zero |
가정이 적용되도록 CPPUNIT_ASSERT_MESSAGE
매크로에서 조건을 부정한다. Listing 5에는 조건이 s.size() ==0
인 경우의 코드 출력이 표시된다.
Listing 5. 조건 s.size( ) == 0이 포함된 Listing 3의 코드 출력
[arpan@tintin] ./a.out OK (1 tests) |
TestRunner
는 단일 테스트 또는 테스트 스위트를 실행하는 유일한 방법은 아니다. CppUnit은 대체 클래스 계층 구조—즉, 템플리트화된 TestCaller
클래스—를 제공하여 테스트를 실행한다. runTest
메소드 대신 TestCaller
클래스를 사용하여 모든 메소드를 실행할 수 있다. Listing 6에 간단한 예제가 제공된다.
Listing 6. TestCaller를 사용하여 테스트 실행하기
class ComplexNumberTest ... { public: void ComplexNumberTest::testEquality( ) { … } }; CppUnit::TestCaller<ComplexNumberTest> test( "testEquality", &ComplexNumberTest::testEquality ); CppUnit::TestResult result; test.run( &result ); |
위 예제에서 ComplexNumberText
유형의 클래스는 testEquality
메소드로 두 복소수의 동일성을 테스트하여 정의된다. TestCaller
는 TestRunner
의 경우와 마찬가지로 이 클래스를 사용하여 템플리트화되며 사용자는 테스트 실행을 위해 run
메소드에 대한 호출을 작성한다. TestCaller
클래스를 지금 상태대로 사용하는 것은 그다지 효율적이지 않다. TextTestRunner
클래스가 출력의 표시를 자동으로 처리한다. TestCaller
의 경우 별도의 클래스를 사용하여 출력을 처리해야 한다. TestCaller
클래스를 사용하여 사용자 정의된 테스트 스위트를 정의하는 경우 기사 후반부에 이 유형의 코드 플로우가 표시된다.
CppUnit은 가장 일반적인 가정 시나리오에 대한 몇 가지 루틴을 제공한다. 이러한 루틴은 Asserter.h 헤더에서 사용할 수 있는 CppUnit::Asserter
클래스의 공용 정적 메소드로 정의된다. TestAssert.h 헤더에는 이러한 클래스 대부분에 대한 사전 정의된 매크로도 있다. Listing 2를 근거로 하여 CPPUNIT_ASSERT_MESSAGE
는 다음과 같이 정의된다(Listing 7 참조).
Listing 7. CPPUNIT_ASSERT_MESSAGE의 정의
#define CPPUNIT_ASSERT_MESSAGE(message,condition) \ ( CPPUNIT_NS::Asserter::failIf( !(condition), \ CPPUNIT_NS::Message( "assertion failed", \ "Expression: " \ #condition, \ message ), \ CPPUNIT_SOURCELINE() ) ) |
가정의 근거가 되는 failIf
메소드의 선언이 Listing 8에 제공된다.
Listing 8. failIf 메소드의 선언
struct Asserter { … static void CPPUNIT_API failIf( bool shouldFail, const Message &message, const SourceLine &sourceLine = SourceLine() ); … } |
failIf
메소드의 조건이 True가 되면 예외가 발생한다. run
메소드는 이 프로세스를 내부적으로 처리한다. 하지만 흥미롭고 유용한 또다른 매크로인 CPPUNIT_ASSERT_DOUBLES_EQUAL
이 있다. 이 매크로는 허용 값으로 두 double 간 동일성을 검사한다(따라서, |expected – actual | ≤ delta
). Listing 9에는 매크로 정의가 제공된다.
Listing 9. CPPUNIT_ASSERT_DOUBLES_EQUAL 매크로 정의
void CPPUNIT_API assertDoubleEquals( double expected, double actual, double delta, SourceLine sourceLine, const std::string &message ); #define CPPUNIT_ASSERT_DOUBLES_EQUAL(expected,actual,delta) \ ( CPPUNIT_NS::assertDoubleEquals( (expected), \ (actual), \ (delta), \ CPPUNIT_SOURCELINE(), \ "" ) ) |
mystring
클래스의 여러 패싯을 테스트하는 한 가지 방법은 runTest
메소드 내에 검사를 계속 추가하는 것이다. 하지만 아주 단순한 클래스를 제외하고는 이 방법을 사용하면 관리가 어려워진다. 여기서 테스트 스위트를 정의하고 사용해야 한다. 문자열 클래스에 대한 테스트 스위트를 정의하는 Listing 10을 살펴본다.
Listing 10. 문자열 클래스에 대한 테스트 스위트 만들기
#include <cppunit/extensions/TestFactoryRegistry.h> #include <cppunit/ui/text/TextTestRunner.h> #include <cppunit/extensions/HelperMacros.h> class mystringTest : public CppUnit::TestCase { public: void checkLength() { mystring s; CPPUNIT_ASSERT_MESSAGE("String Length Non-Zero", s.size() == 0); } void checkValue() { mystring s; s.setbuffer("hello world!\n"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Corrupt String Data", s[0], 'w'); } CPPUNIT_TEST_SUITE( mystringTest ); CPPUNIT_TEST( checkLength ); CPPUNIT_TEST( checkValue ); CPPUNIT_TEST_SUITE_END(); }; |
Listing 10은 매우 단순하다. CPPUNIT_TEST_SUITE
매크로를 사용하여 테스트 스위트를 정의한다. mystringTest
클래스의 일부인 개별 메소드는 테스트 스위트에서 유닛 테스트를 형성한다. 잠시 후에 이러한 매크로와 컨텐츠에 대해 살펴본다. 하지만 먼저 이 테스트 스위트를 사용하는 Listing 11의 클라이언트 코드를 살펴본다.
Listing 11. mystring 클래스에 대한 테스트 스위트를 사용하는 클라이언트 코드
CPPUNIT_TEST_SUITE_REGISTRATION ( mystringTest ); int main () { CppUnit::Test *test = CppUnit::TestFactoryRegistry::getRegistry().makeTest(); CppUnit::TextTestRunner runner; runner.addTest(test); runner.run(); return 0; } |
Listing 12에는 Listing 11에 있는 코드가 실행될 때의 출력이 표시된다.
Listing 12. Listings 10 및 11의 코드 출력
[arpan@tintin] ./a.out !!!FAILURES!!! Test Results: Run: 2 Failures: 2 Errors: 0 1) test: mystringTest::checkLength (F) line: 26 str.cc assertion failed - Expression: s.size() == 0 - String Length Non-Zero 2) test: mystringTest::checkValue (F) line: 32 str.cc equality assertion failed - Expected: h - Actual : w - Corrupt String Data |
CPPUNIT_ASSERT_EQUAL_MESSAGE
는 TestAssert.h 헤더에 정의되어 있으며 예상 인수와 실제 인수가 일치하는지 확인한다. 일치하지 않는 경우에는 지정된 메시지가 표시된다. HelperMacros.h에 정의된 CPPUNIT_TEST_SUITE
매크로는 테스트 스위트 작성 및 이 테스트 스위트에 대한 개별 테스트 추가를 단순화한다. 내부적으로 CppUnit::TestSuiteBuilderContext
유형의 템플리트화된 오브젝트가 작성되고(CppUnit 컨텍스트에 있는 테스트 스위트의 동등 항목임) CPPUNIT_TEST
에 대한 각각의 호출은 해당 클래스 메소드를 이 스위트에 추가한다. 말할 필요도 없이 코드에 대한 유닛 테스트 역할을 하는 것은 클래스 메소드이다. 매크로의 순서를 기록한다. 코드가 개별 CPPUNIT_TEST
매크로를 컴파일하려면 CPPUNIT_TEST_SUITE
매크로와 CPPUNIT_TEST_SUITE_END
매크로 사이에 있어야 한다.
개발자는 시간이 흐를수록 코드에 기능을 계속 추가하기 때문에 추가적인 테스트가 필요하다. 동일한 테스트 스위트에 테스트를 계속 추가하면 시간이 흐를수록 더 복잡해지기 때문에 처음 테스트를 개발할 때 의도한 점진적인 변화의 의미를 잃게 된다. 다행히도 CppUnit에는 기존 테스트 스위트를 확장하는 데 사용할 수 있는 CPPUNIT_TEST_SUB_SUITE
라는 유용한 매크로가 있다. Listing 13에서는 이 매크로를 사용한다.
Listing 13. 테스트 스위트 확장하기
class mystringTestNew : public mystringTest { public: CPPUNIT_TEST_SUB_SUITE (mystringTestNew, mystringTest); CPPUNIT_TEST( someMoreChecks ); CPPUNIT_TEST_SUITE_END(); void someMoreChecks() { std::cout << "Some more checks...\n"; } }; CPPUNIT_TEST_SUITE_REGISTRATION ( mystringTestNew ); |
새 클래스 mystringTestNew
는 이전 myStringTest
클래스에서 파생된다. CPPUNIT_TEST_SUB_SUITE
매크로는 새 클래스와 상위 클래스를 두 개의 인수로 승인한다. 클라이언트측에서는 두 클래스 모두를 등록하는 대신 새 클래스만 등록한다. 이것으로 충분하다. 구문의 나머지 부분은 테스트 스위트를 작성하는 경우와 거의 동일하다.
고정 기능(또는 CppUnit 컨텍스트의 TestFixture
)은 개별 테스트에 대한 깔끔한 설정 및 종료 루틴을 제공하기 위한 것이다. 고정 기능을 사용하려면 CppUnit::TestFixture
에서 테스트 킅래스를 파생하고 사전 정의된 setUp
및 tearDown
메소드를 대체한다. setUp
메소드는 유닛 테스트 실행 전에 호출되고 tearDown
은 테스트가 실행될 때 호출된다. Listing 14에는 TestFixture
를 사용하는 방법이 표시된다.
Listing 14. 테스트 고정 기능을 사용하여 테스트 스위트 만들기
#include <cppunit/extensions/TestFactoryRegistry.h> #include <cppunit/ui/text/TextTestRunner.h> #include <cppunit/extensions/HelperMacros.h> class mystringTest : public CppUnit::TestFixture { public: void setUp() { std::cout << “Do some initialization here…\n”; } void tearDown() { std::cout << “Cleanup actions post test execution…\n”; } void checkLength() { mystring s; CPPUNIT_ASSERT_MESSAGE("String Length Non-Zero", s.size() == 0); } void checkValue() { mystring s; s.setbuffer("hello world!\n"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Corrupt String Data", s[0], 'w'); } CPPUNIT_TEST_SUITE( mystringTest ); CPPUNIT_TEST( checkLength ); CPPUNIT_TEST( checkValue ); CPPUNIT_TEST_SUITE_END(); }; |
Listing 15에는 Listing 14의 코드 출력이 표시된다.
Listing 15. Listing 14의 코드 출력
[arpan@tintin] ./a.out . Do some initialization here… FCleanup actions post test execution… . Do some initialization here… FCleanup actions post test execution… !!!FAILURES!!! Test Results: Run: 2 Failures: 2 Errors: 0 1) test: mystringTest::checkLength (F) line: 26 str.cc assertion failed - Expression: s.size() == 0 - String Length Non-Zero 2) test: mystringTest::checkValue (F) line: 32 str.cc equality assertion failed - Expected: h - Actual : w - Corrupt String Data |
이 출력에서 볼 수 있듯이 유닛 테스트 실행당 한 번씩 설정 및 분석 루틴 메시지가 표시된다.
헬퍼 매크로를 사용하지 않고 테스트 스위트를 작성할 수 있다. 한 스타일을 다른 스타일 대신 사용해도 특별한 혜택은 없지만 비매크로 스타일 코딩을 사용하면 디버깅이 더 편하다. 매크로 없이 테스트 스위트를 작성하려면 CppUnit::TestSuite
를 인스턴스화한 후 개별 테스트를 스위트에 추가한다. 마지막으로 run
메소드 호출 전에 스위트 자체를 CppUnit::TextTestRunner
에 전달한다. Listing 16에서 알 수 있듯이 클라이언트측 코드는 거의 동일한 상태를 유지한다.
Listing 16. 헬퍼 매크로 없이 테스트 스위트 작성하기
int main () { CppUnit::TestSuite* suite = new CppUnit::TestSuite("mystringTest"); suite->addTest(new CppUnit::TestCaller<mystringTest>("checkLength", &mystringTest::checkLength)); suite->addTest(new CppUnit::TestCaller<mystringTest>("checkValue", &mystringTest::checkLength)); // client code follows next CppUnit::TextTestRunner runner; runner.addTest(suite); runner.run(); return 0; } |
Listing 16의 내용을 이해하려면 CppUnit 네임스페이스의 두 클래스(TestSuite.h와 TestCaller.h에 각각 선언되어 있는 TestSuite
및 TestCaller
)에 대해 이해해야 한다. runner.run()
호출이 실행되면 각 개별 runTest
메소드가 각각의 개별 TestCaller
오브젝트에 대한 CppUnit에 대해 내부적으로 호출된 후 TestCaller<mystringTest>
생성자에 전달된 것과 동일한 루틴을 호출한다. Listing 17에는 각 스위트에 대해 개별 테스트가 호출되는 방법에 대해 설명하는 CppUnit 소스의 코드가 표시된다.
Listing 17. 스위트에서 실행된 개별 테스트
void TestComposite::doRunChildTests( TestResult *controller ) { int childCount = getChildTestCount(); for ( int index =0; index < childCount; ++index ) { if ( controller->shouldStop() ) break; getChildTestAt( index )->run( controller ); } } |
TestSuite
클래스는 CppUnit::TestComposite
에서 파생된다.
단일 조작에 TextTestRunner
오브젝트를 사용하여 여러 테스트 스위트를 작성한 후 실행할 수 있다. Listing 18에 표시된 대로 Listing 16에서와 같이 각 테스트 스위트를 작성한 후 동일한 addTest
메소드를 TextTestRunner
에 추가하기만 하면 된다.
Listing 18. TextTestRunner를 사용하여 여러 스위트 실행하기
CppUnit::TestSuite* suite1 = new CppUnit::TestSuite("mystringTest"); suite1->addTest(…); … CppUnit::TestSuite* suite2 = new CppUnit::TestSuite("mymathTest"); … suite2->addTest(…); CppUnit::TextTestRunner runner; runner.addTest(suite1); runner.addTest(suite2); … |
지금까지는 테스트의 출력이 TextTestRunner
클래스에 의해 기본적으로 생성되었다. 하지만 CppUnit을 사용하면 출력에 사용자 정의 형식을 사용할 수 있다. 이를 위해 사용할 수 있는 클래스 중 하나는 CompilerOutputter.h 헤더에 선언된 CompilerOutputter
이다. 무엇보다도 이 클래스를 사용하면 출력에 파일 이름 행 번호 정보를 표시하는 데 필요한 형식을 지정할 수 있다. 또한 로그를 화면에서 덤프하는 것과는 반대로 파일에 직접 저장할 수 있다. Listing 19에는 파일에 덤프되는 출력의 예제가 제공된다. %p:%l
형식을 살펴보자. 전자는 파일의 경로를 표시하고 후자는 행 번호를 표시한다. 이 형식을 사용하면 일반적으로 /home/arpan/work/str.cc:26과 같은 출력이 발생한다.
Listing 19. 사용자 정의된 형식을 사용하여 테스트 출력의 경로를 로그 파일로 재지정하기
#include <cppunit/extensions/TestFactoryRegistry.h> #include <cppunit/ui/text/TextTestRunner.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/CompilerOutputter.h> int main () { CppUnit::Test *test = CppUnit::TestFactoryRegistry::getRegistry().makeTest(); CppUnit::TextTestRunner runner; runner.addTest(test); const std::string format("%p:%l"); std::ofstream ofile; ofile.open("run.log"); CppUnit::CompilerOutputter* outputter = new CppUnit::CompilerOutputter(&runner.result(), ofile); outputter->setLocationFormat(format); runner.setOutputter(outputter); runner.run(); ofile.close(); return 0; } |
CompilerOutputter
에는 덤프하는 전반적인 정보의 서브세트를 가져오는 데 사용할 수 있는 printStatistics
및 printFailureReport
와 같은 다른 유용한 메소드의 호스트가 있다.
지금까지는 기본적으로 TextTestRunner
를 사용하여 테스트를 실행해 왔다. TextTestRunner
유형의 오브젝트를 인스턴스화한 후 테스트 및 출력기를 추가한 다음 run
메소드를 호출하기만 하면 되었다. TestRunner
(TextTestRunner
의 수퍼클래스)와 리스너라는 클래스의 새 범주를 사용하여 지금 이 플로우를 벗어나 보자. 각각의 개별 테스트를 수행하는 데 걸리는 시간을 추적하려고 한다고 가정해 보자(성능 벤치마크를 수행하는 개발자에게 일반적으로 발생함). 자세히 설명하기 전에 Listing 20을 살펴보자. 이 코드는 TestListener
에서 파생되는 세 가지 클래스(TestRunner
, TestResult
및 myListener
)를 사용한다. Listing 10에 있는 것과 동일한 mystringTest
클래스를 사용한다.
Listing 20. TestListener 클래스 살펴보기
class myListener : public CppUnit::TestListener { public: void startTest(CppUnit::Test* test) { std::cout << "starting to measure time\n"; } void endTest(CppUnit::Test* test) { std::cout << "done with measuring time\n"; } }; int main () { CppUnit::TestSuite* suite = new CppUnit::TestSuite("mystringTest"); suite->addTest(new CppUnit::TestCaller<mystringTest>("checkLength", &mystringTest::checkLength)); suite->addTest(new CppUnit::TestCaller<mystringTest>("checkValue", &mystringTest::checkLength)); CppUnit::TestRunner runner; runner.addTest(suite); myListener listener; CppUnit::TestResult result; result.addListener(&listener); runner.run(result); return 0; } |
Listing 21에는 Listing 20의 출력이 표시된다.
Listing 21. Listing 20의 코드 출력
[arpan@tintin] ./a.out starting to measure time done with measuring time starting to measure time done with measuring time |
myListener
클래스는 CppUnit::TestListener
에서 서브클래스화된다. startTest
및 endTest
메소드를 적절하게 대체해야 하며 이러한 메소드는 각 테스트의 전과 후에 각각 실행된다. 이러한 메소드를 쉽게 확장하여 개별 테스트에 소요되는 시간을 확인할 수 있다. 그러니 이 기능을 설정/분석 루틴에 추가해 보자. 이 기능을 추가할 수 있지만 추가하게 되면 이는 각 테스트 스위트의 설정/분석 메소드에서 코드가 중복됨을 의미한다.
다음으로 run
메소드에서 TestResult
유형의 인수를 가져오는 TestRunner
클래스의 인스턴스인 실행 프로그램 오브젝트를 살펴본다. 리스너가 TestResult
오브젝트에 추가된다.
마지막으로 출력에 변화가 생겼는가? TextTestRunner
에서는 run
메소드 뒤에 많은 정보가 표시되었지만 TestRunner
에는 이러한 정보가 없다. 필요한 것은 테스트 실행 중에 리스너 오브젝트가 수집한 정보를 표시하는 출력기 오브젝트이다. Listing 22에는 Listing 20에서 변경해야 하는 항목이 표시된다.
Listing 22. 테스트 실행 정보를 표시하는 데 필요한 출력기 추가하기
runner.run(result); CppUnit::CompilerOutputter outputter( &listener, std::cerr ); outputter.write(); |
하지만 잠시 기다리자. 이 방법도 코드를 컴파일하기에는 충분하지 않다. CompilerOutputter
의 생성자는 TestResultCollector
유형의 오브젝트를 예상하며 TestResultCollector
는 TestListener
(세부 사항은 CppUnit 클래스 계층 구조의 링크에 대한 참고자료 참조)에서 파생되기 때문에 TestResultCollector
에서 myListener
를 파생하기만 하면 된다. Listing 23에는 컴파일이 표시된다.
Listing 23. TestResultCollector에서 리스너 클래스 파생하기
class myListener : public CppUnit::TestResultCollector { … }; int main () { … myListener listener; CppUnit::TestResult result; result.addListener(&listener); runner.run(result); CppUnit::CompilerOutputter outputter( &listener, std::cerr ); outputter.write(); return 0; } |
출력이 Listing 24에 표시된다.
Listing 24. Listing 23의 코드 출력
[arpan@tintin] ./a.out starting to measure time done with measuring time starting to measure time done with measuring time str.cc:31:Assertion Test name: checkLength assertion failed - Expression: s.size() == 0 - String Length Non-Zero str.cc:31:Assertion Test name: checkValue assertion failed - Expression: s.size() == 0 - String Length Non-Zero Failures !!! Run: 0 Failure total: 2 Failures: 2 Errors: 0 |
이 기사에서는 CppUnit 프레임워크의 특정 클래스(TestResult
, TestListener
, TestRunner
, CompilerOutputter
등)에 초점을 두었다. 독립형 유닛 테스트 프레임워크로서 CppUnit에는 제공할 수 있는 것이 더 많이 있다. XML 출력 생성을 위해 CppUnit에 클래스(XMLOutputter
)가 있고 GUI 모드에 실행 중인 테스트(MFCTestRunner
및 QtTestRunner
)가 있으며 플러그인 인터페이스(CppUnitTestPlugIn
)도 있다. CppUnit 문서에서 클래스 계층 구조를 살펴보고 설치와 함께 제공되는 예제에서 자세한 내용을 살펴봐야 한다.
교육
- CppUnit 문서: Sourceforge.com에서 프로젝트 페이지를 살펴보자.
- Wikipedia의 CppUnit: Wikipedia에는 CppUnit에 대한 적절한 정보와 기타 유닛 테스트 프레임워크에 대한 링크가 포함되어 있다.
- AIX와 UNIX developerWorks 영역: AIX와 UNIX 영역에서는 AIX 시스템 관리와 UNIX 스킬 확장의 모든 측면과 관련된 풍부한 정보를 제공한다.
- AIX와 UNIX 입문 AIX와 UNIX 입문 페이지에서 자세한 정보를 볼 수 있다.
- developerWorks 기술 행사 및 웹 캐스트: 최신 기술에 대한 정보를 얻을 수 있다.
- 기술 서점: 다양한 기술 주제와 관련된 서적을 살펴볼 수 있다.
제품 및 기술 얻기
- CppUnit 다운로드: CppUnit의 최신 버전을 다운로드하자.
- IBM 제품 평가판: DB2®, Lotus®, Rational®, Tivoli® 및 WebSphere®의 애플리케이션 개발 도구 및 미들웨어 제품을 사용해 볼 수 있다.
토론
- developerWorks 블로그: 블로그를 읽어 보고 developerWorks community에 참여하자.
- Twitter의 developerWorks 페이지를 살펴보자.
- My developerWorks 커뮤니티에 참여하자.
- AIX 및 UNIX 포럼에 참여하자.
- AIX Forum
- AIX Forum for developers
- Cluster Systems Management
- IBM Support Assistant Forum
- Performance Tools Forum
- Virtualization Forum
- 기타 AIX and UNIX Forums
'MS > C++' 카테고리의 다른 글
멀티바이트 --> 유니코드 (매크로) (0) | 2012.11.20 |
---|---|
boost library 설치 방법 (0) | 2012.08.10 |
특정 Thread가 종료 되었는지 대기중인지 알수 있는 코드 (0) | 2012.08.10 |
OpenMP (0) | 2012.07.23 |
ms에서 dirent.h파일 사용 하기 (0) | 2012.06.08 |
SetThreadAffinityMask : 멀티 쓰레드 프로그래밍 기본 (0) | 2012.05.23 |
ActiveX 제작시 Visat/Win7에서 주의해야 할 사항 (0) | 2011.11.18 |
gsoap (0) | 2011.11.08 |
IE8에서 ActiveX 디버깅이 되지 않을 때 (0) | 2011.10.05 |
파일 시스템 정보 얻기 (WM_DEVICECHANGE) (1) | 2010.11.05 |