dev tech

Google Test framework의 기본개념 및 사용법

갬짱 2024. 5. 20. 22:18

 
운영체제 lab 개발하면서 google test framework를 처음으로 사용해보았습니다. 기본개념 및 사용법을 기억하기 위해 기록합니다!!

 

Google Test framework

: 호스트 PC 환경 혹은 서버 개발 환경에서 실제와 비슷하게 동작할 수 있는 테스트 환경( H/W를 mocking을 통해 S/W만으로 테스트 가능 )
 
::testing( ::gtest ) : Google Test 프레임워크에서 사용되는 네임스페이스(namespace), 테스트 관련 기능들이 구현( TEST를 비롯한 매크로 & 함수 )

  • ASSERT_EQ(A, B); - Fail되는 순간 테스트가 멈춤
  • EXPECT_EQ(A, B); - 결과 값 Pass/Fail 여부에 상관없이 계속 진행하고, 마지막에 Fail 된 테스트를 알려준다.
for (int i = 0; i < sizeof(x); ++i) {
  EXPECT_EQ(x[i], y[i]);
}

 

기본개념 및 구조

 
Test Case : 개별적인 기능, 동작을 테스트

  • TEST() : 하나의 함수를 테스트 → TEST( 소속되는 suite, 개별 case이름 )

 
Test Suite : 하나 이상의 테스트 케이스를 포함

/*
TEST(TestSuiteName, TestName) {
		...
}
*/

// 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);
}

 
 
Test Fixture : 실행 전후에 필요한 환경을 설정 → 여러 테스트 케이스에서 공통된 데이터(공유 데이터 및 객체 )나 동작이 필요할 경우에 활용
 
(1) Google Test 프레임워크에서 제공하는 기본 테스트 케이스 클래스(::testing::Test) 상속하여 클래스 생성 → SetUp과 TearDown을 오버라이딩

  • SetUp() : 테스트 케이스가 실행되기 전에 호출되는 함수 / 사전에 준비된 데이터 세팅, 초기화 → 동일한 상태에서 테스트
  • 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_;
};

 
(2) 테스트 픽스처의 실제 적용 및 구현
: TEST_F( 구현한 테스트 픽스쳐, 테스트케이스 이름 )

/*
TEST_F(TestFixtureName, TestName) {
  ... test body ...
}
*/

//IsEmptyInitially : q0이 비어있는지 확인하는 테스
TEST_F(QueueTest, IsEmptyInitially) {
  EXPECT_EQ(q0_.size(), 0);
}

//DequeueWorks : Deque가 동작하는지 확인하는 테스트
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;
}

 


 

테스트케이스의 파라미터화로 활용
 

동작방식 : INSTANTIATE_TEST_CASE_P 매크로의 MyTestFixture와 TEST_P 매크로의 TestCaseName가 일치할때 인스턴스화하는 대상으로 인식한다.
 
[ main ] - 테스트를 실행하는 소스파일
::testing::InitGoogleTest(); 구글 테스트 프레임워크 초기화
RUN_ALL_TESTS() : 등록된 모든 테스트를 실행


[ test.cpp ] - 테스트환경을 구축하는 소스파일
 
INSTANTIATE_TEST_CASE_P() : 파라미터화된 테스트 케이스를 인스턴스화하는 매크로( 생성 & 데이터 전달 ) -> 특정한 로직의 테스트 케이스를 다양한 입력 값과 함께 여러 번 실행가능

INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator_function);
  • prefix : 인스턴스 이름의 접두사(prefix) / 인스턴스의 자동생성 이름앞에 붙게됨
  • test_case_name : 테스트 케이스 이름, 미리 정의된 테스트 케이스를 가리키는 포인터
  • generator_function : 파라미터 값을 생성하는 함수, 각 테스트 케이스에 전달될 파라미터를 생성

=> 이로써 ::testing::Values에서 정의된 워크로드 수 * TEST_P()에서 정의된 테스트케이스 수 만큼의 테스트가 수행된다!!!
 
 
(1) ::testing::Values(Param1, Param2, …): 각 인자값들을 가지고 각기 다른 테스트 케이스 인스턴스를 생성하는 매크로( 인자값만큼의 테스트케이스를 생성 )
다양한 종류의 워크로드를 가지고 정의된 테스트를 실행해볼 수 있다.
 

::testing::Values(
	// std::make_tuple("워크로드 파일", "context_switch 시간"),
	std::make_tuple("A", 0.01),
	std::make_tuple("A", 0.1),
	std::make_tuple("B", 0.05),
	std::make_tuple("B", 0.2)
)

⇒ 각 테스트 케이스에 워크로드파일 & context_switch 시간 정보를 전달
 
(2) TEST_P() : 파라미터화된 테스트 케이스를 정의

TEST_P(TestCaseName, TestName) {
	// 테스트 로직
}
  • TestCaseName: 테스트 케이스의 이름 / 파라미터화된 테스트 케이스 클래스(상속받게 정의한 클래스)의 이름과 동일
  • TestName: 테스트 함수의 이름 / 파라미터화된 테스트 케이스 클래스 안에서 유일

 
[ test_util.cpp ] - 테스트 내용을 정의하는 소스파일
class XXXXtest : TestWithParam(::testing::TestWithParam<std::tuple<자료형, 자료형>>)을 상속받는 사용자 정의 테스트 클래스

  • 여러 파라미터 값( <std::tuple<자료형, 자료형>> )에 대해 동일한 테스트를 반복해서 수행가능 ↔ testng::Test상속은 단일값만 테스트
  • 테스트 클래스를 여러개 구축하고 TEST_P()에서 testcase name으로 각각 입력가능

 
** 해당 상속클래스의 구성 **
(1) 테스트에 이용되는 각종 멤버변수
(2) 테스트에 이용되는 각종 멤버함수
(3) SetUp() 오버라이딩
(4) TearDown() 오버라이딩

'dev tech' 카테고리의 다른 글

[C++] 디자인패턴 RAII를 이용한 자원관리  (1) 2024.06.11
Make 및 Makefile의 개념 및 사용  (0) 2024.05.20
WSL(Windows Subsystem for Linux)의 개념과 기본명령  (0) 2024.05.20
Git  (0) 2024.03.10