본문 바로가기

TA(Test Automation)

GoogleTest + GoogleMock Manual Build Guide (MinGW)

728x90

GoogleTest + GoogleMock Manual Build Guide (MinGW)

이 문서는 Windows 환경에서 MinGW (Qt 포함) 및 PowerShell을 이용해 GoogleTest + GoogleMock을 수동으로 빌드하고 테스트 실행하는 방법을 정리한 가이드입니다.


✅ 사전 준비

  • MinGW 경로: D:/Qt/Tools/mingw1310_64/bin
  • googletest 소스: D:/googletest
  • 테스트 소스: D:/test.cpp

1. googletest 빌드 준비

cd D:/googletest
mkdir build
cd build

🔹 PATH에 MinGW 추가

$env:PATH = "D:/Qt/Tools/mingw1310_64/bin;" + $env:PATH

2. CMake로 Makefile 생성

cmake .. -G "MinGW Makefiles" `
  -DBUILD_GMOCK=ON `
  -DBUILD_GTEST=ON `
  -DCMAKE_BUILD_TYPE=Release

✅ 한 줄 명령:

cmake .. -G "MinGW Makefiles" -DBUILD_GMOCK=ON -DBUILD_GTEST=ON -DCMAKE_BUILD_TYPE=Release

3. Make로 GTest/GMock 빌드

mingw32-make -j

4. 테스트 코드 수동 빌드

g++ -std=c++17 -D_POSIX_C_SOURCE=200809L -fno-strict-aliasing -g -o test.exe test.cpp `
  -I./googletest/googletest/include `
  -I./googletest/googlemock/include `
  -L./googletest/build/lib `
  -lgmock -lgtest -pthread

✅ 한 줄 명령:

g++ -std=c++17 -D_POSIX_C_SOURCE=200809L -fno-strict-aliasing -g -o test.exe test.cpp -I./googletest/googletest/include -I./googletest/googlemock/include -L./googletest/build/lib -lgmock -lgtest -pthread

5. 테스트 실행

./test.exe

✅ 성공 출력 예시

[ RUN      ] MockTest.WorksInCygwin
[INFO] Calling mock.value()...
[INFO] Got result: 42
[       OK ] MockTest.WorksInCygwin (0 ms)
[  PASSED  ] 1 test.

🔚 요약

단계 명령 요약

CMake cmake .. -G "MinGW Makefiles" ...
빌드 mingw32-make -j
테스트 빌드 g++ ... -lgmock -lgtest
실행 ./test.exe

🔄 다음 단계 (선택 사항)

✅ 자동화 옵션

  • build.bat 스크립트를 만들어 수동 빌드를 자동화할 수 있습니다.
  • VSCode의 tasks.json에 등록하여 Ctrl+Shift+B로 빌드 가능
  • launch.json으로 디버깅 연동 가능

✅ 다중 테스트 파일 지원

  • 여러 .cpp 테스트 파일을 하나로 컴파일하여 통합 테스트 가능
  • 예: g++ main.cpp test_math.cpp test_io.cpp ...

✅ 라이브러리 설치 없이 사용

  • libgmock.a, libgtest.a를 프로젝트 내부에 보관하여 별도 설치 없이 사용 가능

🧼 참고 팁

  • PowerShell에서 rm -rf 대신:
Remove-Item * -Recurse -Force
  • 줄바꿈 없이 붙여넣기 원하면 backtick(`) 없이 한 줄로 입력

📁 build.bat 예시

아래는 수동 입력을 자동화하는 build.bat 예시입니다.

@echo off
setlocal

set MINGW=D:/Qt/Tools/mingw1310_64/bin
set PATH=%MINGW%;%PATH%

cd /d %~dp0\googletest
if not exist build mkdir build
cd build

cmake .. -G "MinGW Makefiles" -DBUILD_GMOCK=ON -DBUILD_GTEST=ON -DCMAKE_BUILD_TYPE=Release
if errorlevel 1 exit /b

mingw32-make -j || exit /b

cd /d %~dp0
%MINGW%/g++.exe -std=c++17 -D_POSIX_C_SOURCE=200809L -fno-strict-aliasing -g -o test.exe test.cpp ^
  -I./googletest/googletest/include ^
  -I./googletest/googlemock/include ^
  -L./googletest/build/lib ^
  -lgmock -lgtest -pthread
// complete_gtest_demo.cpp
// 이 파일은 Google Test 및 Google Mock의 주요 매크로와 기능을 포괄하는 통합 테스트 예제입니다.
// 포함된 항목:
// - 기본 단정 매크로 (EXPECT_TRUE, ASSERT_EQ 등)
// - 비교/부동소수점/문자열/예외 단정
// - 프레디케이트 단정 (EXPECT_PREDn, EXPECT_PRED_FORMATn)
// - TEST_F (Fixture 기반), TEST_P (매개변수화 테스트)
// - 사용자 정의 매크로
// - GTEST_SKIP, SCOPED_TRACE, HasFailure
// - Death test (EXPECT_DEATH) 및 death_test_style 설정
// - Google Mock: MOCK_METHOD, EXPECT_CALL, StrictMock, InSequence
// - static_assert, std::is_same 기반 타입 검사

#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <stdexcept>
#include <cmath>
#include <cstring>
#include <string>
#include <iostream>
#include <cstdlib>
#include <type_traits>
#include <windows.h>

// =======================
// 테스트 대상 함수 정의
// =======================
int add(int a, int b) { return a + b; }
float add_float(float a, float b) { return a + b; }
double add_double(double a, double b) { return a + b; }
void throws_if_negative(int x) { if (x < 0) throw std::runtime_error("Negative!"); }
bool is_positive(int x) { return x > 0; }
void fatal_function() { std::abort(); }

::testing::AssertionResult is_even(const char* expr1, const char* expr2, int a, int b) {
    if ((a + b) % 2 == 0)
        return ::testing::AssertionSuccess();
    return ::testing::AssertionFailure() << expr1 << " + " << expr2 << "의 합은 홀수입니다.";
}

bool is_sorted(int a, int b, int c) { return a <= b && b <= c; }
::testing::AssertionResult is_sorted_fmt(const char* a_expr, const char* b_expr, const char* c_expr, int a, int b, int c) {
    if (a <= b && b <= c) return ::testing::AssertionSuccess();
    return ::testing::AssertionFailure() << a_expr << ", " << b_expr << ", " << c_expr << " => 정렬되지 않음: " << a << ", " << b << ", " << c;
}

// =======================
// 사용자 정의 단정 매크로
// =======================
#define MY_EXPECT_POSITIVE(x) EXPECT_TRUE((x) > 0) << "Expected value to be positive, but got: " << (x)

// =======================
// 일반 단정 매크로
// =======================
TEST(GeneralAssertions, TruthChecks) {
    EXPECT_TRUE(add(1, 2) == 3);           // true
    EXPECT_FALSE(add(1, 2) == 4);          // false
    ASSERT_TRUE(add(2, 2) == 4);           // true, 실패 시 중단
    ASSERT_FALSE(add(2, 2) == 5);          // false, 실패 시 중단
}

// =======================
// 비교 단정 매크로
// =======================
TEST(ComparisonAssertions, IntegerChecks) {
    EXPECT_EQ(add(1, 2), 3);               // ==
    EXPECT_NE(add(1, 2), 4);               // !=
    EXPECT_LT(add(1, 2), 5);               // <
    EXPECT_LE(add(2, 2), 4);               // <=
    EXPECT_GT(add(3, 3), 5);               // >
    EXPECT_GE(add(3, 3), 6);               // >=

    ASSERT_EQ(add(2, 2), 4);               // ==
    ASSERT_NE(add(2, 2), 5);               // !=
    ASSERT_LT(add(1, 1), 3);               // <
    ASSERT_LE(add(2, 2), 4);               // <=
    ASSERT_GT(add(4, 1), 4);               // >
    ASSERT_GE(add(4, 1), 5);               // >=
}

// =======================
// 부동소수점 비교 매크로
// =======================
TEST(FloatingPoint, FloatAndDouble) {
    EXPECT_FLOAT_EQ(add_float(0.1f, 0.2f), 0.3f);     // float ==
    EXPECT_DOUBLE_EQ(add_double(0.1, 0.2), 0.3);      // double ==
    EXPECT_NEAR(add_double(1.0, 2.0), 3.0, 1e-9);     // |a - b| <= epsilon
    ASSERT_FLOAT_EQ(add_float(0.5f, 0.5f), 1.0f);     // float ==
    ASSERT_DOUBLE_EQ(add_double(0.3, 0.3), 0.6);      // double ==
    ASSERT_NEAR(add_double(1.0, 1.0), 2.0, 1e-9);     // |a - b| <= epsilon
}

// =======================
// 문자열 비교 매크로
// =======================
TEST(StringAssertions, CStringComparisons) {
    const char* a = "Hello";
    const char* b = "Hello";
    const char* c = "World";

    EXPECT_STREQ(a, b);                    // ==
    EXPECT_STRNE(a, c);                    // !=
    EXPECT_STRCASEEQ("hello", "HELLO");   // == ignoring case
    EXPECT_STRCASENE("hello", "world");   // != ignoring case

    ASSERT_STREQ(a, b);
    ASSERT_STRNE(a, c);
    ASSERT_STRCASEEQ("hello", "HELLO");
    ASSERT_STRCASENE("hello", "world");
}

// =======================
// 예외 검사 매크로
// =======================
TEST(ExceptionAssertions, ThrowChecks) {
    EXPECT_THROW(throws_if_negative(-1), std::runtime_error);  // throw
    EXPECT_ANY_THROW(throws_if_negative(-99));                 // any throw
    EXPECT_NO_THROW(throws_if_negative(1));                    // no throw

    ASSERT_THROW(throws_if_negative(-1), std::runtime_error);
    ASSERT_ANY_THROW(throws_if_negative(-99));
    ASSERT_NO_THROW(throws_if_negative(1));
}

// =======================
// 프레디케이트 단정 매크로
// =======================
TEST(PredicateAssertions, PredicateChecks) {
    EXPECT_PRED1(is_positive, 10);        // is_positive(x)
    ASSERT_PRED1(is_positive, 100);
}

TEST(PredicateAssertions, PredicateFormatChecks) {
    EXPECT_PRED_FORMAT2(is_even, 1, 1);   // (1 + 1) % 2 == 0
    ASSERT_PRED_FORMAT2(is_even, 2, 2);
}

TEST(PredicateAssertions, Predicate3) {
    EXPECT_PRED3(is_sorted, 1, 2, 3);     // 1 <= 2 <= 3
    ASSERT_PRED_FORMAT3(is_sorted_fmt, 3, 2, 1); // 실패 예시
}

// =======================
// Fixture 기반 테스트
// =======================
class MyFixture : public ::testing::Test {
protected:
    void SetUp() override { a = 10; b = 20; }
    void TearDown() override {
        if (::testing::Test::HasFailure()) std::cout << "Test failed.\n";
    }
    int a, b;
};

TEST_F(MyFixture, AddInFixture) {
    EXPECT_EQ(add(a, b), 30);
}

// =======================
// 매개변수화 테스트
// =======================
class ParamTest : public ::testing::TestWithParam<int> {};

TEST_P(ParamTest, IsEvenParam) {
    int n = GetParam();
    EXPECT_EQ(n % 2, 0);                 // 짝수 확인
}

INSTANTIATE_TEST_SUITE_P(EvenNumbers, ParamTest, ::testing::Values(2, 4, 6));

// =======================
// 유용 기능 매크로
// =======================
TEST(SkipTest, SkipExample) {
    GTEST_SKIP() << "이 테스트는 조건에 따라 건너뜁니다.";
}

TEST(ScopedTraceExample, TraceOnFailure) {
    SCOPED_TRACE("디버그: 현재 실패 원인 추적 중");
    EXPECT_EQ(1, 2);                     // 실패
}

TEST(FailureCheckTest, DetectFailureAndSkip) {
    EXPECT_EQ(1, 2);                     // 실패
    if (::testing::Test::HasFailure()) {
        std::cout << "실패 발생 감지됨\n";
        GTEST_SKIP() << "실패로 인해 이후 절차 생략";
    }
}

// =======================
// Death Test
// =======================
TEST(DeathTest, AbortCausesDeath) {
    EXPECT_DEATH(fatal_function(), "");  // std::abort
}

// =======================
// Google Mock 예제
// =======================
class Calculator {
public:
    virtual ~Calculator() = default;
    virtual int multiply(int x, int y) = 0;
};

class MockCalculator : public Calculator {
public:
    MOCK_METHOD(int, multiply, (int x, int y), (override));
};

TEST(GMockTest, ExpectCallSuccess) {
    MockCalculator calc;
    EXPECT_CALL(calc, multiply(2, 3)).Times(1).WillOnce(::testing::Return(6));
    EXPECT_EQ(calc.multiply(2, 3), 6);
}

class MockPrinter {
public:
    MOCK_METHOD(void, printHeader, (), ());
    MOCK_METHOD(void, printBody, (), ());
    MOCK_METHOD(void, printFooter, (), ());
};

TEST(GMockTest, StrictOrderTest) {
    ::testing::StrictMock<MockPrinter> printer;
    {
        ::testing::InSequence seq;
        EXPECT_CALL(printer, printHeader());
        EXPECT_CALL(printer, printBody());
        EXPECT_CALL(printer, printFooter());
    }

    printer.printHeader();
    printer.printBody();
    printer.printFooter();
}

// =======================
// 타입 검사
// =======================
template<typename T, typename U>
void check_same_type() {
    static_assert(std::is_same<T, U>::value, "타입이 다릅니다!");
}

TEST(TypeTraitsTest, SameTypeCheck) {
    check_same_type<int, int>();
    // check_same_type<int, float>(); // 주석 해제 시 컴파일 에러
}

// =======================
// main 함수
// =======================
int main(int argc, char** argv) {
    SetConsoleOutputCP(CP_UTF8);
    ::testing::InitGoogleTest(&argc, argv);
    ::testing::GTEST_FLAG(death_test_style) = "threadsafe";
    return RUN_ALL_TESTS();
}


 

PS D:\> $env:PATH = "D:/Qt/Tools/mingw1310_64/bin;" + $env:PATH                                                                                   
PS D:\> chcp 65001                                                                                                                                   
Active code page: 65001
PS D:\> g++ -std=c++17 -D_POSIX_C_SOURCE=200809L -fno-strict-aliasing -g -o test.exe test.cpp -I./googletest/googletest/include -I./googletest/googlemock/include -L./googletest/build/lib -lgmock -lgtest -pthread
PS D:\> ./test


[==========] Running 19 tests from 14 test suites.
[----------] Global test environment set-up.
[----------] 1 test from DeathTest
[ RUN      ] DeathTest.AbortCausesDeath
[       OK ] DeathTest.AbortCausesDeath (13 ms)
[----------] 1 test from DeathTest (18 ms total)

[----------] 1 test from GeneralAssertions
[ RUN      ] GeneralAssertions.TruthChecks
[       OK ] GeneralAssertions.TruthChecks (0 ms)
[----------] 1 test from GeneralAssertions (5 ms total)

[----------] 1 test from ComparisonAssertions
[ RUN      ] ComparisonAssertions.IntegerChecks
[       OK ] ComparisonAssertions.IntegerChecks (0 ms)
[----------] 1 test from ComparisonAssertions (4 ms total)

[----------] 1 test from FloatingPoint
[ RUN      ] FloatingPoint.FloatAndDouble
[       OK ] FloatingPoint.FloatAndDouble (0 ms)
[----------] 1 test from FloatingPoint (4 ms total)

[----------] 1 test from StringAssertions
[ RUN      ] StringAssertions.CStringComparisons
[       OK ] StringAssertions.CStringComparisons (0 ms)
[----------] 1 test from StringAssertions (4 ms total)

[----------] 1 test from ExceptionAssertions
[ RUN      ] ExceptionAssertions.ThrowChecks
[       OK ] ExceptionAssertions.ThrowChecks (0 ms)
[----------] 1 test from ExceptionAssertions (4 ms total)

[----------] 3 tests from PredicateAssertions
[ RUN      ] PredicateAssertions.PredicateChecks
[       OK ] PredicateAssertions.PredicateChecks (0 ms)
[ RUN      ] PredicateAssertions.PredicateFormatChecks
[       OK ] PredicateAssertions.PredicateFormatChecks (0 ms)
[ RUN      ] PredicateAssertions.Predicate3
test.cpp:140: Failure
3, 2, 1 => 정렬되지 않음: 3, 2, 1

[  FAILED  ] PredicateAssertions.Predicate3 (3 ms)
[----------] 3 tests from PredicateAssertions (17 ms total)

[----------] 1 test from MyFixture
[ RUN      ] MyFixture.AddInFixture
[       OK ] MyFixture.AddInFixture (0 ms)
[----------] 1 test from MyFixture (4 ms total)

[----------] 1 test from SkipTest
[ RUN      ] SkipTest.SkipExample
test.cpp:175: Skipped
이 테스트는 조건에 따라 건너뜁니다.

[  SKIPPED ] SkipTest.SkipExample (3 ms)
[----------] 1 test from SkipTest (7 ms total)

[----------] 1 test from ScopedTraceExample
[ RUN      ] ScopedTraceExample.TraceOnFailure
test.cpp:180: Failure
Expected equality of these values:
  1
  2
Google Test trace:
test.cpp:179: 디버그: 현재 실패 원인 추적 중

[  FAILED  ] ScopedTraceExample.TraceOnFailure (6 ms)
[----------] 1 test from ScopedTraceExample (11 ms total)

[----------] 1 test from FailureCheckTest
[ RUN      ] FailureCheckTest.DetectFailureAndSkip
test.cpp:184: Failure
Expected equality of these values:
  1
  2

실패 발생 감지됨
test.cpp:187: Skipped
실패로 인해 이후 절차 생략

[  FAILED  ] FailureCheckTest.DetectFailureAndSkip (6 ms)
[----------] 1 test from FailureCheckTest (11 ms total)

[----------] 2 tests from GMockTest
[ RUN      ] GMockTest.ExpectCallSuccess
[       OK ] GMockTest.ExpectCallSuccess (0 ms)
[ RUN      ] GMockTest.StrictOrderTest
[       OK ] GMockTest.StrictOrderTest (0 ms)
[----------] 2 tests from GMockTest (8 ms total)

[----------] 1 test from TypeTraitsTest
[ RUN      ] TypeTraitsTest.SameTypeCheck
[       OK ] TypeTraitsTest.SameTypeCheck (0 ms)
[----------] 1 test from TypeTraitsTest (4 ms total)

[----------] 3 tests from EvenNumbers/ParamTest
[ RUN      ] EvenNumbers/ParamTest.IsEvenParam/0
[       OK ] EvenNumbers/ParamTest.IsEvenParam/0 (0 ms)
[ RUN      ] EvenNumbers/ParamTest.IsEvenParam/1
[       OK ] EvenNumbers/ParamTest.IsEvenParam/1 (0 ms)
[ RUN      ] EvenNumbers/ParamTest.IsEvenParam/2
[       OK ] EvenNumbers/ParamTest.IsEvenParam/2 (0 ms)
[----------] 3 tests from EvenNumbers/ParamTest (14 ms total)

[----------] Global test environment tear-down
[==========] 19 tests from 14 test suites ran. (190 ms total)
[  PASSED  ] 15 tests.
[  SKIPPED ] 1 test, listed below:
[  SKIPPED ] SkipTest.SkipExample
[  FAILED  ] 3 tests, listed below:
[  FAILED  ] PredicateAssertions.Predicate3
[  FAILED  ] ScopedTraceExample.TraceOnFailure
[  FAILED  ] FailureCheckTest.DetectFailureAndSkip

 3 FAILED TESTS

 

728x90

'TA(Test Automation)' 카테고리의 다른 글

googleTest + win app driver + vs2022  (0) 2025.04.18
appium, python, android, 테스트 자동화  (0) 2025.01.14
googletest VSCODE C/C++  (0) 2025.01.10
python unittest - assertEqual  (0) 2024.08.26