본문 바로가기
GTEST

[GTEST] "--gtest_filter" 옵션으로 설정한 테스트 케이스가 존재하지 않는 경우 오류 처리 방법

by Junk_Seo 2023. 11. 30.
반응형

1. 개요

  • GTEST의 경우 filter 옵션으로 특정 테스트 케이스를 실행시킬 수 있습니다.
  • 하지만 옵션으로 준 테스트 케이스가 존재하지 않는 경우 따로 오류 처리를 하지 않아 개별 테스트를 여러 번 수행하는 경우 테스트 케이스 누락 여부를 확인하기 어려워 내용을 정리합니다.
  • 비교

    테스트가 있는 경우 테스트가 없는 경우

2. GTEST에서 제공하는 Class를 사용하여 처리하는 방법

  • GTEST에서는 테스트 프로그램에 대한 정보를 가지고 있는 Class를 제공합니다.
  • 이를 활용하여 옵션으로 주어진 테스트 케이스가 존재하는지 체크하는 방법을 확인합니다.
  • 사용 Class
    • UnitTest : 테스트 프로그램 전체 상태를 반영합니다.
    • TestCase : 테스트 케이스에 대한 정보가 있으며, 테스트 케이스는 테스트를 하나 이상 포함하고 있습니다.
    • TestInfo : 테스트 상태에 대한 정보가 있습니다.
  • 사용한 Class 말고도 제공되는 Class들이 있지만 여기에서는 위 3개만 사용했습니다. (다른 Class 정보는 GTEST 문서를 확인 바랍니다.)

2.1. 테스트 소스

  • 예제 소스 일부
    ...
    const ::testing::UnitTest* pUnitTest = ::testing::UnitTest::GetInstance();
     
    for(i = 0; i < pUnitTest->total_test_case_count(); i++)
    {
        const ::testing::TestCase* pTestCase = pUnitTest->GetTestCase(i);
     
        for(j = 0; j < pTestCase->total_test_count(); j++)
        {
            const ::testing::TestInfo* pTestInfo = pTestCase->GetTestInfo(j);
            printf("[%s].[%s] \n", pTestCase->name(), pTestInfo->name());
        }
    }
    ...​
  • 결과
  • 위 소스는 GTEST의 전체 테스트 케이스별 테스트 목록을 출력할 수 있도록 합니다.
  • RUN_ALL_TESTS(); 호출 전에 개별 테스트 케이스 실행 시 해당 테스트 케이스와 테스트를 비교하여 존재 유무를 확인합니다.

2.2. 문제점

  • 입력으로 받은(명령 인수 등) 테스트 케이스와 테스트를 전체 테스트 케이스와 테스트 목록에서 확인하여 존재 유무를 확인해야 하므로 이를 위한 코드가 증가합니다.
  • 와일드 카드(* 등)를 사용하는 경우 이를 처리하기 위한 예외 처리도 추가되어야 합니다.
  • RUN_ALL_TESTS(); 호출 이후에는 현재 테스트 케이스와 테스트를 확인할 수 있지만, 목록에 없는 테스트 케이스와 테스트를 호출하는 경우 테스트를 수행하지 않기 때문에 처리가 불가능합니다.

2.3. 결론

  • 해당 방법으로 처리하기 위해 추가하는 소스 코드가 많아 효율적이지 않습니다.
  • 따라서 해당 방법을 사용하지 않습니다

3. 항상 실행되는 테스트 케이스를 추가하여 체크하는 처리하는 방법

  • 항상 실행되는 테스트 케이스의 테스트를 추가하여 체크하는 방법을 확인합니다.
  • RUN_ALL_TESTS() 호출 이후에 SetUp()에서 실행 테스트 개수를 체크하는 방식을 사용합니다.

3.1. 테스트 소스

  • 샘플 소스
    #include <stdio.h>
    #include <assert.h>
     
    #include "gtest/gtest.h"
    #include "main.h"
    #include "cal.h"
     
    CEnvironment::CEnvironment()
    {
    }
     
    CEnvironment::CEnvironment(int argc, char **argv) : bRunTestChk(false), bRunChk(false), pszTargetType(NULL)
    {
        int i = 0, j = 0;
        char *pszTmp = NULL;
     
        for(i = 1; i < argc; i++)
        {
            pszTmp = strstr(argv[i], "target");
            if (NULL != pszTmp)
            {
                pszTargetType = argv[i + 1];
                i++;
                continue;
            }
        }
     
        /* 명령인수로 들어온 테스트 케이스와 테스트를 처리하는 부분 */
        if(NULL != pszTargetType)	//29번 라인
        {
            bRunChk = true;
            ::testing::GTEST_FLAG(filter) = "TEST_ALWAYS.ALWAYS_RUN_TEST:";
            ::testing::GTEST_FLAG(filter) += pszTargetType;
        }
        else
        {
            bRunChk = false;
        }
    }
     
    CEnvironment::~CEnvironment()
    {
        bRunTestChk = false;
        bRunChk = false;
        pszTargetType = NULL;
    }
     
    void CEnvironment::SetUp()	// 48번 라인
    {
        int nTestRunCount = 0;
        const ::testing::UnitTest *pUnitTest = :: testing::UnitTest::GetInstance();
        nTestRunCount = pUnitTest->test_to_run_count();
        printf("run test count = [%d]\n", nTestRunCount);
        if(1 == nTestRunCount)
        {
            bRunTestChk = false;
        }
        else
        {
            bRunTestChk = true;
        }
    }
     
    void CEnvironment::TearDown()
    {
    }
     
    bool CEnvironment::GetRunTestChk()
    {
        return bRunTestChk;
    }
     
    bool CEnvironment::GetRunChk()
    {
        return bRunChk;
    }
     
    char *CEnvironment::GetTargetType()
    {
        return pszTargetType;
    }
     
    TEST(TEST_ALWAYS, ALWAYS_RUN_TEST)	// 83번 라인
    {
        EXPECT_TRUE(g_Env->GetRunTestChk());
    }
     
    TEST(SUM_TEST1, SUM_TEST_1)
    {
        EXPECT_EQ(2, Add(1, 1));
    }
     
    TEST(SUM_TEST1, SUM_TEST_2)
    {
        EXPECT_EQ(3, Add(1, 2));
        EXPECT_EQ(1, Add(1, 0));
        EXPECT_EQ(2, Add(1, 1));
    }
     
    TEST(MINUS_TEST1, MINUS_TEST_1)
    {
        EXPECT_EQ(2, Minus(3, 1));
    }
     
    TEST(MINUS_TEST1, MINUS_TEST_2)
    {
        EXPECT_EQ(3, Minus(4, 1));
        EXPECT_EQ(1, Minus(2, 1));
        EXPECT_EQ(2, Minus(3, 1));
    }
     
    TEST(MUL_TEST1, MUL_TEST_1)
    {
        EXPECT_EQ(2, Mul(2, 1));
    }
     
    TEST(MUL_TEST1, MUL_TEST_2)
    {
        EXPECT_EQ(3, Mul(3, 1));
        EXPECT_EQ(4, Mul(4, 1));
        EXPECT_EQ(5, Mul(5, 1));
    }
     
    TEST(DIV_TEST1, DIV_TEST_1)
    {
        EXPECT_EQ(2, Div(4, 2));
    }
     
    TEST(DIV_TEST1, DIV_TEST_2)
    {
        EXPECT_EQ(3, Div(3, 1));
        EXPECT_EQ(1, Div(1, 1));
        EXPECT_EQ(5, Div(10, 2));
    }
     
    CEnvironment* g_Env = NULL;
     
    int main(int argc, char **argv)
    {
        g_Env = new CEnvironment(argc, argv);	// 140번 라인
     
        if (false == g_Env->GetRunChk())
        {
            printf("%s, line %d\n", __FILE__, __LINE__);
            exit(-1);
        }
     
        ::testing::InitGoogleTest(&argc, argv);
        ::testing::AddGlobalTestEnvironment(g_Env);
     
        return RUN_ALL_TESTS();
    }​
  • 소스 설명
    • 140번 라인 : 명령 인수로 테스트 케이스와 테스트 이름을 입력받아 생성자에서 처리합니다.
    • 29번 라인 : GTEST filter FLAG에 항상 실행하는 테스트와 입력받은 테스트를 설정합니다.
    • 48번 라인 : RUN_ALL_TESTS() 호출 이후 SetUp()에서 실행할 테스트의 개수를 체크합니다. (1 이면 항상 실행하는 테스트만 수행하므로 예외 처리를 위한 값을 세팅합니다.)
    • 83번 라인 : 수행할 다른 테스트가 없다면 오류가 발생되도록 합니다.

3.2. 테스트 및 결과

  • 테스트 및 결과
    테스트가 있는 경우 테스트가 없는 경우
  • 테스트가 있는 경우 실행 테스트의 개수가 2개로 되어 정상 처리
  • 테스트가 없는 경우 실행 테스트의 개수가 1개로 되어 실패 처리

3.3. 결론

  • 무조건 Dummy 테스트가 실행되어야 한다는 문제는 있지만 첫 번째 방법보다는 간편하다는 장점이 있습니다.
반응형