개발/개발 환경

[개발 환경] 구글 테스트(googletest) 개념 및 예제

growing-dev 2023. 2. 5. 21:12

Goggletest의 개념에 대해서 알아보고 Goggle에서 제공하는 예제를 통해 Googletest의 활용법을 익혀보도록 한다.

Googletest의 개념과 예제

  • Googletest란
  • Googletest 예제

 

 

Googletest란

https://github.com/google/googletest

 

GitHub - google/googletest: GoogleTest - Google Testing and Mocking Framework

GoogleTest - Google Testing and Mocking Framework. Contribute to google/googletest development by creating an account on GitHub.

github.com

구글 테스트는 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를 테스트 픽스처를 사용하기 위해 구현한 공식 예제이다.

QueueTest라는 클래스를 ::testing::Test로부터 상속 받고 SetUp()과 TearDown()을 구현한다. 아래 예제에서는 SetUp()에서 q1,q2에 데이터를 넣고, TearDown()은 불필요해서 구현하지 않았다.
 
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;
}

 

결론

구글 테스트 공식 예제와 설명을 통해 구글 테스트가 어떤 것이고 어떤 식으로 구현해야 하는지 간단하게 알아보았다. 다음에는 실제 프로젝트에 어떻게 적용하는지 알아보고 내 프로젝트에 구현해 보면서 활용해 볼 예정이다.

반응형