Goggletest의 개념에 대해서 알아보고 Goggle에서 제공하는 예제를 통해 Googletest의 활용법을 익혀보도록 한다.
Googletest의 개념과 예제
- Googletest란
- Googletest 예제
Googletest란
https://github.com/google/googletest
구글 테스트는 C/C++ 테스트를 하기 위한 구글에서 제공하는 툴/프레임워크라고 볼 수 있다. 소프트웨어를 개발하고 검증할 때 필요한 유닛테스트나 통합테스트를 구현하려면 실제 소프트웨어가 돌아가는 환경과 다소 다른 환경에서 동작할 필요가 있을 때가 있다. 예를 들어 칩이나 SOC에서 동작하는 펌웨어나 응용프로그램을 테스트하기 위해서는 전통적으로 실제 타깃에 다운로드하고 실 환경과 비슷하게 동작해 보면서 여러 가지 테스트를 할 수밖에 없다. 하지만 현실적으로 H/W가 아직 개발이 되지 않았거나 리소스가 부족하거나 환경을 구성하는 데에 많은 비용과 노력이 든다면 굉장히 비효율적이고 시간과 비용이 많이 들 것이다. 따라서 우리는 호스트 PC 환경 혹은 서버 개발 환경에서 실제와 비슷하게 동작할 수 있는 테스트 환경이 필요하고 이런 수단을 제공하는 것이 테스트 프레임워크이고 이 중에 C/C++에서 대표적으로 많이 사용되고 있는 것이 Googletest이다. 즉 우리는 Googletest를 활용해서 H/W를 mocking 할 수 있고 이를 통해 H/W 없이 S/W 만으로 테스트가 가능해지며 단위 테스트와 통합 테스트 수준을 쉽게 구현함으로써 소프트웨어 자동화된 테스트를 수행할 수 있고 나아가 소프트웨어의 전반적인 품질을 향상할 수 있다.
Googletest 예제
Google에서 제공하는 Googletest 예제를 분석해보고 추후 프로젝트에 어떻게 활용될 수 있을지 생각해 볼 것이다.
Googletest에서 가장 기본 되는 개념은 Pass/Fail을 판단하는 Assert이다. Assert의 결과로 Pass/Fail을 판단한다. 또한 Test Suite는 하나 이상의 테스트를 포함하고 더 확장해서 Test Fixture를 활용할 수 있다.
Assert를 사용하는 방법은 아래와 같다.
이때 ASSERT는 Fail되는 순간 테스트가 멈추는데 비해, EXPECT는 결과 값 Pass/Fail 여부에 상관없이 계속 진행하고, 마지막에 Fail 된 테스트를 알려준다.
ASSERT_EQ(A, B) //A와 B가 다르면 Fail
//x와 y의 인자를 index별로 각각 비교해서 다르면 Fail
for (int i = 0; i < sizeof(x); ++i) {
EXPECT_EQ(x[i], y[i]);
}
기본적인 테스트 구조
TEST(TestSuiteName, TestName) {
...
}
테스트를 작성할 때 TEST() 함수를 통해 작성한다. 하나의 TEST() 내에서 하나의 함수를 테스트하는 것이 일반적이다.
Test Suite Name은 하나의 Test Suite를 함께 공유하면서 Name은 따로 가져가는 것이 좋다.
// Tests factorial of 0.
TEST(FactorialTest, HandlesZeroInput) {
EXPECT_EQ(Factorial(0), 1);
}
// Tests factorial of positive numbers.
TEST(FactorialTest, HandlesPositiveInput) {
EXPECT_EQ(Factorial(1), 1);
EXPECT_EQ(Factorial(2), 2);
EXPECT_EQ(Factorial(3), 6);
EXPECT_EQ(Factorial(8), 40320);
}
위의 예시는 공식 문서에도 나와 있는 예시이다. 위와 같이 Factorial이라는 함수를 테스트하기 위해 2가지의 테스트 케이스를 만들었다. 가장 중요한 것은 테스트 코드를 보았을 때 간단명료하고 이름이나 코드를 보았을 때 바로 이해할 수 있어야 좋은 테스트 코드라고 할 수 있을 것이다.
Test Fixture
테스트 픽스처는 여러 테스트 케이스에서 공통된 데이터나 동작이 필요할 경우에 활용하는 방법이다.
::testing::Test 라는 클래스를 상속받고 SetUp()과 TearDown()을 통해 매 테스트 케이스마다 공통적이고 동일한 동작을 수행할 수 있도록 한다. 예를 들어 어떤 모듈을 테스트하려고 할 때 사전에 미리 준비된 데이터가 필요하거나 초기화가 필요하거나 하는 경우에 SetUp()을 통해서 테스트마다 동일한 상태에서 테스트할 수 있도록 만들어 줄 수 있고 또 하나의 테스트가 끝나면 기존의 상태로 원복 하거나 불필요한 데이터를 지우는 등의 동작을 TearDown()에서 수행하여 각 테스트마다 독립적으로 구성할 수 있도록 해야 한다.
테스트 픽스처는 아래와 같이 기존 TEST()가 아닌 TEST_F()로 구현해야 하며 TestFixfureName 부분이 생성되는 클래스 이름이어야 한다.
TEST_F(TestFixtureName, TestName) {
... test body ...
}
아래는 Queue를 테스트 픽스처를 사용하기 위해 구현한 공식 예제이다.
class QueueTest : public ::testing::Test {
protected:
void SetUp() override {
// q0_ remains empty
q1_.Enqueue(1);
q2_.Enqueue(2);
q2_.Enqueue(3);
}
// void TearDown() override {}
Queue<int> q0_;
Queue<int> q1_;
Queue<int> q2_;
};
실제 테스트를 구현하면 아래와 같다. q0는 별도로 SetUp()에서 건드리지 않았으므로 비어있어서 size가 0인 것을 테스트하는 테스트가 첫 번째로 있다. 그다음은 Deque가 동작하는지 확인하는 테스트이다. 픽스처에 QueueTest가 정의되어 있으니 위에서 정의했던 클래스가 매 테스트 케이스마다 생성되면서 q1, q2에 데이터가 들어가 있게 된다. q1에는 1이라는 데이터 하나가 들어가 있을 것이다. 따라서 Deque를 한 다음 null이 아닌지 체크하고, 꺼낸 값이 1인지 확인한 다음 현재 q1이 비어있음을 확인하는 테스트가 그다음에 있다. 그 다음 q2 테스트는 동일하게 꺼내고 꺼낸 값이 null이 아닌지 체크하고 값이 2인지 확인 후 현재 1개(데이터 3)가 남아 있는지 체크하는 테스트가 나온다.
TEST_F(QueueTest, IsEmptyInitially) {
EXPECT_EQ(q0_.size(), 0);
}
TEST_F(QueueTest, DequeueWorks) {
int* n = q0_.Dequeue();
EXPECT_EQ(n, nullptr);
n = q1_.Dequeue();
ASSERT_NE(n, nullptr);
EXPECT_EQ(*n, 1);
EXPECT_EQ(q1_.size(), 0);
delete n;
n = q2_.Dequeue();
ASSERT_NE(n, nullptr);
EXPECT_EQ(*n, 2);
EXPECT_EQ(q2_.size(), 1);
delete n;
}
결론
구글 테스트 공식 예제와 설명을 통해 구글 테스트가 어떤 것이고 어떤 식으로 구현해야 하는지 간단하게 알아보았다. 다음에는 실제 프로젝트에 어떻게 적용하는지 알아보고 내 프로젝트에 구현해 보면서 활용해 볼 예정이다.
'개발 > 개발 환경' 카테고리의 다른 글
[윈도우11] 부팅 시 자동 시작 프로그램 등록, 확인 및 해제하는 방법 (1) | 2023.02.22 |
---|---|
[개발 환경] CMake 프로젝트에 Googletest 추가하기 (0) | 2023.02.05 |
[개발 환경] CMake 프로젝트 구성하기 - 다양한 변수들 (2) | 2023.02.01 |
[개발 환경] CMake 프로젝트 구성하기 - 프로젝트 관련 명령어들 (1) | 2023.01.30 |
[개발 환경] CMake 프로젝트 구성하기 - 스크립트 관련 명령어들 (0) | 2023.01.29 |