카테고리 없음

Google Test의 데이터 기반 테스트

wafe 2009. 5. 23. 03:36

Google Test에서도 MBUnit의 RowTestNUnit의 TestCase 같은 데이터 기반 테스트라는 개념을 지원한다. Google Test에서는 이 개념을 Value-Parameterized Tests라고 부른다. 코드는 동일한데 사용하는 데이터 값 몇 개만 바뀌는 테스트 케이스가 있을 때, 코드 중복을 없애주면서도 어떤 테스트 케이스가 실패하고 성공하는지 정확하게 알려주는 유용한 기능이다.

 

그런데 아무래도 C# 보다는 유연성이 떨어지는(?) C++이라 쓰기가 마냥 쉽지만은 않아서 좀 정리를 해 둘 필요가 있다. 템플릿을 써서 구현한 기능이라 컴파일 에러라도 한 번 나면 좀 골치가 아프긴 하지만, Visual C++ 2008의 템플릿 관련 에러 메시지는 엄청나게 친절하기 때문에 미리 걱정할 필요는 없을 듯.

  1. #include "gtest/gtest.h"

    #include "gmock/gmock.h"

    #include <tuple>

     

    using testing::Return;

     

    namespace

    {

    // ParamType 구성

    // TestWithParam<T>가 받는 테스트 데이터는 T 타입의 값 하나이기 때문에, 데이터 여러 개를 넘기려고 tuple을 사용한다.

    typedef std::tr1::tuple<bool, MsoTriState, MsoAnimateByLevel, MsoTriState, MsoTriState, MsoAnimateByLevel> ParamType;

     

    // Value-Parameterized Tests를 위해서는 비어있는 Fixture라도 하나 만들어야한다.

    // TestWithParam<T>를 상속받는 것 외에는 일반적인 Test Fixture와 동일하다.

    class TestEffectDataSetEffectInformationFixture

        : public testing::TestWithParam<ParamType>

    {

    };

     

    // Value-Parameterized Tests를 위한 테스트 메서드

    // 여기서는 TEST_P 매크로를 쓴다. 일반적인 Fixture를 쓸 때에는 TEST_F 매크로를 쓰는 것과 다르다.

    TEST_P(TestEffectDataSetEffectInformationFixture, TestSetEffectInformation)

    {

        bool recheckRun;

        MsoTriState recheckRetValue;

        MsoAnimateByLevel levelEffectRetValue;

        MsoTriState animBgRetValue;

        MsoTriState animBgExpected;

        MsoAnimateByLevel levelEffectExpected;

     

        // GetParam() 함수를 써서 테스트 데이터를 얻는다.

        // 여기서는 데이터가 tuple 이라서 tie()를 써서 값을 얻는다.

        std::tr1::tie(recheckRun, recheckRetValue, levelEffectRetValue, animBgRetValue, animBgExpected, levelEffectExpected) = GetParam();

     

        MockEffectAdaptor ea;

        MockEffectInformationAdaptor eia;

     

        if (recheckRun) {

            EXPECT_CALL(ea, GetAnimateBackgroundRechecked())

                .WillOnce(Return(recheckRetValue));

        }

        else {

            EXPECT_CALL(ea, GetAnimateBackgroundRechecked())

                .Times(0);

        }

     

        EXPECT_CALL(eia, GetBuildByLevelEffect())

            .WillOnce(Return(levelEffectRetValue));

        EXPECT_CALL(eia, GetAnimateBackground())

            .WillOnce(Return(animBgRetValue));

     

        EffectData ed;

        ed.SetEffectInformation(ea, eia);

     

        ASSERT_EQ(animBgExpected, ed.AnimateBackground);

        ASSERT_EQ(levelEffectExpected, ed.BuildByLevelEffect);

    }

     

    // Value-Parameterized Tests에 테스트 데이터를 제공

    INSTANTIATE_TEST_CASE_P(Prefix, TestEffectDataSetEffectInformationFixture,

        testing::Values(

            ParamType(true, msoTrue, msoAnimateLevelNone, msoFalse, msoTrue, msoAnimateLevelNone),

            ParamType(true, msoFalse, msoAnimateLevelNone, msoFalse, msoFalse, msoAnimateLevelNone),

            ParamType(false, msoFalse, msoAnimateTextByAllLevels, msoFalse, msoFalse, msoAnimateTextByAllLevels),

            ParamType(false, msoFalse, msoAnimateLevelNone, msoTrue, msoTrue, msoAnimateLevelNone)

        ));

    } // anonymous namespace

 

테스트 실행 결과는 이런 식으로 나온다.

3>[ RUN      ] Prefix/TestEffectDataSetEffectInformationFixture.TestSetEffectInformation/0
3>[       OK ] Prefix/TestEffectDataSetEffectInformationFixture.TestSetEffectInformation/0
3>[ RUN      ] Prefix/TestEffectDataSetEffectInformationFixture.TestSetEffectInformation/1
3>[       OK ] Prefix/TestEffectDataSetEffectInformationFixture.TestSetEffectInformation/1
3>[ RUN      ] Prefix/TestEffectDataSetEffectInformationFixture.TestSetEffectInformation/2
3>[       OK ] Prefix/TestEffectDataSetEffectInformationFixture.TestSetEffectInformation/2
3>[ RUN      ] Prefix/TestEffectDataSetEffectInformationFixture.TestSetEffectInformation/3
3>[       OK ] Prefix/TestEffectDataSetEffectInformationFixture.TestSetEffectInformation/3

 

이 예제 코드에서는 테스트 데이터를 만들 때 그냥 Values()만 썼는데, Combine() 같은 걸 쓰면 주어진 값의 모든 조합을 생성해서 테스트해 준다거나 하는 기능은 그냥 코드 중복을 막는다는 차원을 넘어서는 멋진 기능이라고 생각된다.

 

그 외에 다른 사용법은 공식 문서를 보면 되는데, 실제 사용하면서 생기는 궁금증을 해결하기 위해서는 소스 코드에 주석 형태로 들어있는 사용 예제들을 보는게 좋다.

이 글은 스프링노트에서 작성되었습니다.