Skip to content

Mocking

Franz Miltz edited this page Aug 7, 2021 · 1 revision

Why Mock?

Often when testing a program you will find that there are external dependencies that you do not have access to. This can be a pain for testing as it becomes hard to tell if a test is failing due to these dependencies, so to get around this we mock those dependencies. A mock is just a simulation of another object.

Creating a mocking file

  1. Go to the directory hyped-2021/test/src/<ModuleYouWishToTest>
  2. Create the files <NameOfTest>.test.cpp and <NameOfTest>.test.hpp
  3. At the top of the header file you must include both the google test and google mock library

For Example

If I wished to create a test file for which required mocking the config in utils then each step would look like:

  1. hyped-2021/test/src/utils
  2. config.test.cpp and config.test.hpp
  3. At the top of config.test.hpp I have #include "test/gtest.h" and #include "mock/gmock.h"

Mocking Fundamentals

Mocking in the Header

In the header file you need to create a mock of the class/object you wish to mock. You can only mock the functions of a class/object that are virtual! If a function is not virtual then it means that it is an essential part of the system and you should not be mocking it.

Template for mocking:

class Mock<ClassName> : public <ClassName>
{
 public:
  MOCK_METHOD(<ReturnType>, <MethodName>, (<Args...>), (override));
};

Mocking in the C++ file

In this file you can include test fixtures, individual unit tests and anything else that can be done as before but now you can also add mocks.

Expectations

There are two main types of "assertions" for mocking

ON_CALL

This defines what happens when a mock method is called, but doesn't imply any expectation on the method being called.

EXPECT_CALL

This defines the behaviour but also sets an expectation that the method will be called with the given arguments, for the given number of times, and in the given order. This adds a lot of constraints to the call making you more prone to missing edge cases.

You can also specify how many times you wish for a method to be called as well as what it should return and other exciting possibilities which we encourage you to explore here: https://github.com/google/googletest/blob/master/googlemock/docs/cheat_sheet.md

Mock Test Anatomy

The possibilities for what you can do here are endless but the majority of the time you will be following the same template:

Template

.test.hpp

#include "gtest/gtest.h"
#include "gmock/gmock.h"

#include "<HeaderFileForClassToBeMocked>"
#include "<AnyLibrariesUsedInTesting>"

class Mock<MockedClass> : public <MockedClass>
{
 public:
  MOCK_METHOD(<ReturnType>, <MethodName>, (<Args...>), (override));
  ...
  MOCK_METHOD(<ReturnType>, <MethodName>, (<Args...>), (override));
};

.test.cpp

#include "<ClassTest>.test.hpp"

TEST(<TestFixtureName>, <UniqueUnitTestName>)
{
  // Establish any mocks you need to use here
  Mock<MockedClass> <mockedClass>;

  // Have any calls you want to test for here
  EXPECT_CALL(<mockedClass>, <functionBeingCalled>(<Argument>)).<MANY_OPTIONAL_CONSTRAINTS>;

  // Construct whatever objects you are using for the test
  // (If not already made in a test fixture
  <ObjectToBeTested> <objectToBeTested>(&<mockedClass>);

  // Finally your assertions
  EXPECT_TRUE(<objectToBeTested>.<functionBeingCalled>(<Argument>));
}

Example

compWinner.test.hpp

#include "gtest/gtest.h"
#include "gmock/gmock.h"

#include "HypedMachine.hpp"
#include "CompWinner.hpp"

class MockHypedMachine : public HypedMachine
{
 public:
  MOCK_METHOD(bool, year, int, (override));
};

compWinner.test.cpp

#include "compWinner.test.hpp"
TEST(nextComp, CallsHypedMachineYear)
{
  MockHypedMachine hypedMachine;

  EXPECT_CALL(hypedMachine, year(2021));

  CompWinner compWinner(&hypedMachine);

  EXPECT_TRUE(compWinner.nextComp());
}

So in the above example we are assuming there is a class called HypedMachine with a function called year() which takes in a year and returns true if the HypedMachine will win the competition that year. We however wish to test another class called CompWinner which has a function nextComp() - this returns true if there is a winner for the next competition. nextComp() we are assuming goes through all the teams and will return true if at least one teams year() function returns true. Hence we are testing that the function year() in the HypedMachine is in fact called.

Optional Constraints

Optional constraints can be powerful when used in small quantities but the more you add the more you are overfitting to certain circumstances. The constraints can be added to the EXPECT_CALL or the ON_CALL. E.g EXPECT_CALL(<mockedClass>, <functionBeingCalled>(<Argument>)).<OPTIONAL_CONSTRAINTS>

WillOnce(testing::Return(<value>));

This ensures that the first time <functionBeingCalled> is called it will return <value>. E.g. EXPECT_CALL(hypedMachine, year(2020)).WillOnce(testing::Return(true));.

Clone this wiki locally