[GTest] 일반적인 TEST 방법
개발을 진행하면서 테스트는 반드시 필요한 작업 중 하나라고 생각합니다. (TDD든 뭐든.)
업무 상 가장 많이 사용하고 앞으로도 사용할 것 같은 Google Test를 정리하고자 합니다.
Google Test(이하 gtest)에서는 일반적으로 세 가지 방법의 테스트 케이스 작성 방식을 제공합니다.
- TEST
- TEST_F
- TEST_P
이 세 가지 방식에 대해 정리했습니다.
TEST
TEST(TestSuiteName, TestName)
가장 기본적인 테스트 방식입니다.
독립적으로 동작하는 테스트를 작성할 수 있습니다.
공통 모듈에 대한 테스트 보다는 독립적으로 하나의 함수 또는 단순 입출력과 같은 테스트에 적합합니다.
Example
TEST(MathTest, Plus) {
EXPECT_EQ(1 + 1, 2);
}
TEST(MathTest, Equal) {
ASSERT_TRUE(1 == 1);
}
TEST_F
TEST_F(TestFixtureName, TestName)
TEST_F는 TEST처럼 단일 테스트도 가능하지만
공통 환경(Fixture)을 사용해야 하는 테스트에 사용할 수 있습니다.
::testing::Test를 상속한 클래스를 사용해야 하며,
SetUp/TearDown과 같은 함수를 사용하여 동일한 환경 설정 및 리소스 사용이 가능합니다.
Example
class TestFixture : public ::testing::Test
{
protected:
void SetUp() override
{
std::cout << "테스트 시작 전" << std::endl;
}
void TearDown() override
{
std::cout << "테스트 종료 후" << std::endl;
}
int sum(int a, int b)
{
return a + b;
}
};
TEST_F(TestFixture, TestCaseName)
{
int num = 0;
num = sum(2, 3);
EXPECT_EQ(num, 5);
}
TEST_P
TEST_P(TestFixtureName, TestName)
TEST_P도 TEST처럼 단일 테스트도 가능합니다.
하지만 같은 기능을 여러 입력 값으로 테스트 하려는 경우에 사용할 수 있습니다.
::testing::TestWithParam<T>를 상속한 클래스를 사용해야 하며,
테스트를 만들어도 INSTANTIATE_TEST_SUITE_P를 통해 파라미터를 주지 않으면 동작하지 않습니다.
또한 내부적으로 GetParam 함수를 통해 파라미터를 받아 테스트를 수행합니다.
Example
struct TestParam
{
int num1;
int num2;
int result;
std::string str;
};
class TestFixture : public ::testing::TestWithParam<TestParam>
{
protected:
void SetUp() override
{
std::cout << "테스트 시작 전" << std::endl;
}
void TearDown() override
{
std::cout << "테스트 종료 후" << std::endl;
}
};
TEST_P(TestFixture, TestCaseName)
{
TestParam param = GetParam();
std::cout << param.str << std::endl;
EXPECT_EQ(param.num1 + param.num2, param.result);
}
std::vector<TestParam> TestGroup = {
{1, 1, 2, "Test 1"},
{1, 2, 3, "Test 2"},
{4, 5, 9, "Test 3"},
};
INSTANTIATE_TEST_SUITE_P(TestPrefix, TestFixture, ::testing::ValuesIn(TestGroup));
INSTANTIATE_TEST_SUITE_P
INSTANTIATE_TEST_SUITE_P(InstantiationName, TestSuiteName, param_generator);
INSTANTIATE_TEST_SUITE_P(InstantiationName, TestSuiteName, param_generator, name_generator);
INSTANTIATE_TEST_SUITE_P는 이름에서 유추할 수 있듯 TEST_P로 만들어진 테스트를 인스턴스화하는 매크로입니다.
- InstantiationName : Prefix이며 빈 문자도 가능합니다.
- TestSuiteName : TEST_P에서 정의된 테스트 스위트(클래스)입니다.
- param_generator : 파라미터를 생성하는 부분입니다.
- name_generator : 옵션 값이며, 테스트의 이름을 만드는 suffix입니다.
만들어진 테스트 케이스는 "InstantiationName/TestSuiteName/TestName/Index" 형태로 만들어집니다.
여기서 Index는 name_generator를 사용할 경우 해당 이름으로 지정됩니다.
param_generator
파라미터를 생성하는 부분은 아래와 같이 나뉜다고 한다. (다 써보지는 않음)
| Generator | Description |
|---|---|
| Range(begin, end [, step]) | begin, end 구간 값 |
| Values(v1, .., vN) | 지정된 값들 |
| ValuesIn(container) / ValuesIn(begin, end) | 컨테이너 값 또는 범위 값 |
| Bool() | false, true 값 |
| Combine(g1, .., gN) | 지정된 값들의 모든 조합을 std::tuple형태로 제공 |
| ConvertGenerator<T>(g) | 중간 변환 어댑터 개념 |
- 여기서 ConvertGenerator는 아직 사용해보지 않았습니다.
name_generator
말 그대로 이름을 생성하는 부분입니다.
생략하게 되면 기본적으로 Index가 붙습니다. (0, 1, 2, ...)
std::string(const testing::TestParamInfo<ParamType>&)의 형태를 사용해야 합니다.
테스트 코드에서 GetParam으로 얻는 값은 info.param으로 접근이 가능합니다.
// 람다를 사용한 방식
INSTANTIATE_TEST_SUITE_P(
MyInstantiation, MyTestSuite,
testing::Values(...),
[](const testing::TestParamInfo<MyTestSuite::ParamType>& info) {
// Can use info.param here to generate the test suffix
std::string name = ...
return name;
});
- 중요한 것은 공백이나 금지 문자를 포함해서는 안된다는 점입니다.
std::string이나 C문자열은 사용하지 않습니다. (금지 문자 포함)
아래와 같이 사용할 수도 있습니다.
std::string PrintTestName(const testing::TestParamInfo<TestParam>& info) {
return info.param.str + std::to_string(info.param.result);
}
| 참고 Testing Reference