GoogleTest

repository·main·Indexed 12 days ago

https://github.com/google/googletest

A C++ testing framework based on the xUnit architecture that provides a rich set of assertions, test discovery, and support for death tests and parameterized tests. It includes GoogleMock, a framework for creating and using mock classes with a declarative syntax for defining behavior and validating arguments. Version 1.18.x requires at least C++17.

Tokens
64.1K
Snippets
184
Records
247
Agent score
98%

What's inside GoogleTest

  1. Getting started with GoogleTest

    main
    GoogleTest is a C++ testing and mocking framework. If you are new to the project, start with the GoogleTest Primer to learn how to write simple tests. Once you are comfortable with the basics, you can progress to advanced features, sample implementations, and mocking capabilities.
  2. Overview of the gMock Framework

    main

    gMock is Google's C++ framework for creating and using mock classes. It is designed to help developers derive better system designs and write more effective tests by providing a declarative syntax for defining mocks and controlling their behavior.

    Key capabilities include:

    • Declarative Mock Definition: Define mock objects using a specialized syntax.
    • Partial (Hybrid) Mocks: Create objects that combine real implementation with mocked behavior.
    • Complex Function Support: Handles overloaded functions and functions of arbitrary types.
    • Rich Matcher Set: Validate function arguments using a wide variety of built-in matchers.
    • Behavior Control: Use intuitive syntax to specify how mocks should respond to calls.
    • Automatic Verification: Expectations are verified automatically (no manual record-and-replay required).
    • Ordering Constraints: Express arbitrary (partial) ordering constraints on function calls.
    • Extensibility: Users can define custom matchers and actions.
    • No Exceptions: The framework does not rely on C++ exceptions.
  3. What is a mock object and how does it differ from a fake?

    main

    In testing, a mock object is an object that implements the same interface as a real object but is pre-programmed with expectations. These expectations specify the calls the mock is expected to receive (e.g., which methods are called, in what order, how many times, and with what arguments).

    It is important to distinguish mocks from fake objects:

    • Fakes: Have working implementations but use shortcuts (like an in-memory file system) to make them faster or simpler, making them unsuitable for production.
    • Mocks: Focus on verifying the interaction between the code under test and the dependency by specifying expected behaviors and call patterns.
  4. Handle uninteresting mock calls

    main

    An uninteresting call occurs when a mock method is called, but no EXPECT_CALL has been defined for it. By default, gMock performs a default action and prints a warning, but does not fail the test.

    To manage these:

    • Suppress warnings: Use NiceMock<MockClass> to wrap your mock object. This suppresses all uninteresting call warnings.
    • Allow specific calls: If you want to allow certain calls without strict verification, use EXPECT_CALL(...).Times(AnyNumber()).
    • Avoid over-specification: Do not add EXPECT_CALL just to silence a warning; this makes tests harder to maintain.
    using ::testing::NiceMock;
    
    TEST(MyTest, Example) {
      NiceMock<MockDomainRegistry> mock_registry;
      // No warnings will be printed for calls to mock_registry that aren't explicitly expected
      ...
    }
  5. Choose between Typed Tests and Value-Parameterized Tests

    main

    When testing multiple implementations of the same interface, choose based on how instances are created and how you want failure information reported:

    FeatureTyped TestsValue-Parameterized Tests
    CreationEasier if implementations use the same constructor/factory (e.g., new TypeParam).Easier if implementations require different constructor arguments (e.g., new Foo vs new Bar(5)).
    Failure OutputShows the name of the failing type automatically.Shows the iteration number by default (requires custom name function for better output).
    SafetyRequires explicit casting to the interface type to ensure correct testing.Less prone to mistakes regarding interface vs. concrete type testing.

    Tip: If using value-parameterized tests, pass a function that returns an iteration name as the third parameter to INSTANTIATE_TEST_SUITE_P to improve debuggability.

  6. Verify Mock Expectations on Destruction

    main

    gMock automatically verifies that all expectations set via EXPECT_CALL() have been satisfied when the mock object is destroyed.

    Warning for Heap Allocation: If you allocate mock objects on the heap and they are never deleted, the final verification will not occur. To ensure leaks are caught and mocks are properly verified, it is recommended to use the gtest_main library, which enables the heap checker automatically.

  7. How type-parameterized tests work

    main

    Type-parameterized tests allow you to define test logic once and instantiate it with different sets of types later. This is useful for verifying that different implementations of an interface or concept all satisfy the same requirements without duplicating test code.

    To implement them:

    1. Define a fixture class template.
    2. Declare the suite using TYPED_TEST_SUITE_P(FixtureName).
    3. Define tests using TYPED_TEST_P(FixtureName, TestName). Inside these tests, use TypeParam to refer to the current type.
    4. Register the test patterns using REGISTER_TYPED_TEST_SUITE_P(FixtureName, Test1, Test2, ...).
    5. Instantiate the suite with specific types using INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, FixtureName, TypeList).
    // 1. Define fixture template
    template <typename T>
    class FooTest : public testing::Test {
      void DoSomethingInteresting();
    };
    
    // 2. Declare suite
    TYPED_TEST_SUITE_P(FooTest);
    
    // 3. Define tests
    TYPED_TEST_P(FooTest, DoesBlah) {
      TypeParam n = 0;
      this->DoSomethingInteresting();
    }
    
    // 4. Register patterns
    REGISTER_TYPED_TEST_SUITE_P(FooTest, DoesBlah);
    
    // 5. Instantiate
    using MyTypes = ::testing::Types<char, int, unsigned int>;
    INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes);
  8. Use NiceMock and StrictMock to control uninteresting calls

    main

    An "uninteresting call" is a call to a mock method that has no corresponding EXPECT_CALL. By default, gMock prints a warning for these. You can change this behavior on a per-mock-object basis:

    • NiceMock<T>: Suppresses warnings for uninteresting calls. Use this most of the time to keep tests clean.
    • StrictMock<T>: Treats uninteresting calls as failures. Use this only as a last resort, as it makes tests brittle.
    • Default (Naggy): Prints a warning for uninteresting calls. Useful during active development/debugging.

    Note: These modifiers only work if the MOCK_METHOD is defined directly in the mock class (not in a base class) and if the mock class has a virtual destructor.

    using ::testing::NiceMock;
    using ::testing::StrictMock;
    
    TEST(MyTest, Example) {
      NiceMock<MockFoo> nice_foo;
      StrictMock<MockFoo> strict_foo;
      
      // nice_foo will not warn if methods other than those expected are called.
      // strict_foo will fail if any method other than those expected is called.
    }
  9. Avoid underscores in TEST and TEST_F names

    main

    To prevent invalid C++ identifiers and name collisions, do not use underscores (_) in TestSuiteName or TestName within TEST() or TEST_F() macros.

    Why this matters:

    1. Reserved Identifiers: GoogleTest uses DISABLED_ as a prefix. Additionally, C++ reserves identifiers starting with an underscore followed by an uppercase letter (e.g., _Foo) or containing double underscores (__).

    2. Name Collisions: Using underscores in the middle of names can cause different tests to generate the same internal class name. For example:

      • TEST(Time, Flies_Like_An_Arrow)
      • TEST(Time_Flies, Like_An_Arrow)

      Both would generate the class Time_Flies_Like_An_Arrow_Test, leading to compilation errors.

  10. Use Matchers to specify expected arguments

    main

    Matchers are predicates used within EXPECT_CALL() to validate the arguments passed to a mock method.

    • Wildcard (_): Use _ to indicate that any value for that argument is acceptable. This helps prevent brittle tests by avoiding over-specification.
    • Equality: Providing a literal value (e.g., 100) is implicitly treated as Eq(100), meaning the argument must equal that value.
    • Comparison Matchers: Use built-in matchers like Ge(value) (Greater than or equal to) to express ranges or bounds.

    If a method is overloaded, you must specify the arguments (or matchers) to help gMock resolve which overload you are targeting.

    using ::testing::_;
    using ::testing::Ge;
    ...
    // Matches any value for the second argument
    EXPECT_CALL(turtle, GoTo(50, _));
    
    // Matches any value greater than or equal to 100
    EXPECT_CALL(turtle, Forward(Ge(100)));
  11. Handle fatal failures in sub-routines

    main

    A common pitfall is assuming ASSERT_* or FAIL* aborts the entire test. In reality, they only abort the current function. If an ASSERT_* fails inside a subroutine, the caller will continue execution, which can lead to crashes (e.g., dereferencing a null pointer).

    To handle this, you have three main options:

    1. Use ASSERT_NO_FATAL_FAILURE(statement): This macro checks if the statement generated any fatal failures in the current thread. If it did, the assertion fails and aborts the current test.
    2. Use HasFatalFailure(): Manually check if a fatal failure has occurred and return early from the caller.
    3. Use Exceptions: Implement a custom testing::EmptyTestEventListener that throws a testing::AssertionException when a fatal failure occurs.
    // Option 1: Using ASSERT_NO_FATAL_FAILURE
    ASSERT_NO_FATAL_FAILURE(Foo());
    
    // Option 2: Using HasFatalFailure() to return early
    TEST(FooTest, Bar) {
      Subroutine();
      if (HasFatalFailure()) return;
      // The following won't be executed if Subroutine() had a fatal failure.
    }
  12. Perform Death Tests to verify process termination

    main

    Death tests verify that a piece of code causes the process to terminate. GoogleTest executes the code in a child process to prevent the main test runner from dying.

    Key Assertions

    • EXPECT_DEATH(statement, matcher): Verifies statement causes the process to terminate with a nonzero exit status and produces stderr output matching matcher. A bare string matcher is treated as a regex (ContainsRegex).
    • EXPECT_DEATH_IF_SUPPORTED(statement, matcher): Behaves like EXPECT_DEATH if supported by the platform; otherwise, does nothing.
    • EXPECT_DEBUG_DEATH(statement, matcher): Behaves like EXPECT_DEATH in debug mode; in NDEBUG mode, it simply executes the statement.
    • EXPECT_EXIT(statement, predicate, matcher): Verifies statement terminates with an exit status satisfying predicate and stderr matching matcher.

    Exit Status Predicates

    • ::testing::ExitedWithCode(exit_code): Returns true if the program exited normally with the given code.
    • ::testing::KilledBySignal(signal_number): Returns true if the program was killed by a specific signal (not available on Windows).

    Death Test Styles

    Controlled by the --gtest_death_test_style flag (default is "fast"):

    • "fast": (POSIX) Uses fork()/clone() and executes the statement immediately in the child.
    • "threadsafe": (POSIX/Windows) Re-executes the test binary in the child to ensure a clean environment.
    // Verify process dies with specific error message
    EXPECT_DEATH(DoSomething(42), "My error");
    
    // Verify process exits with code 0 and specific message
    EXPECT_EXIT(NormalExit(), testing::ExitedWithCode(0), "Success");
    
    // Compound statements in death tests
    EXPECT_DEATH({
      int n = 5;
      DoSomething(&n);
    }, "Error on line .* of DoSomething()");