C++
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C++
-
Section 4: Memory Management
-
Section 5: Templates and Generic Programming
-
Section 6: The Standard Template Library
-
Section 7: Modern C++ Features
-
Section 8: Error Handling
-
Section 9: Multithreading
-
Section 10: Operator Overloading and Type Conversion
-
Section 11: Advanced Topics
-
Section 12: Tooling and Build Systems
-
Section 13: Design Patterns in C++
-
Section 14: Interfacing with C and Systems Programming
-
Section 15: Networking and IPC Basics
-
Section 16: Graphics and Game Programming Basics
-
Section 17: The Boost Libraries
-
Section 18: Data Structures and Algorithms in C++
-
Section 19: Practical Projects
-
Section 20: More Concurrency Patterns
-
Section 21: More OOP and Design Practice
-
Section 22: File I/O and Streams
-
Section 23: More Standard Library
-
Section 24: Practice Exercises
-
Section 25: Interview and Algorithm Practice
-
Section 26: Compiler and Language Internals
-
Section 27: GUI and Application Frameworks Overview
-
Section 28: Testing and Quality Practices
-
Section 29: Numerics Library
-
Section 30: Concepts Library (C++20)
-
Section 31: Ranges Library (C++20) In Depth
-
Section 32: More Utility Library
231: Mocking Dependencies with Google Mock
I've been staring at this unit test for twenty minutes, and it's failing for the most annoying reason possible: it requires a physical temperature sensor to be plugged into the USB port. I'm working from home, and I don't have a thermal probe sitting on my desk. This is the classic "dependency nightmare."
The Hardware Headache
Here is the snippet of the code I'm trying to test. It's a simple ClimateController that's supposed to turn on a heater if the room drops below 20 degrees Celsius.
class TemperatureSensor {
public:
float getTemperature() {
// Imagine this talks to a real hardware register
return Hardware::readSensor();
}
};
class ClimateController {
TemperatureSensor& sensor;
public:
ClimateController(TemperatureSensor& s) : sensor(s) {}
bool checkHeatingNeeded() {
return sensor.getTemperature() < 20.0f;
}
};
If I try to write a test for checkHeatingNeeded(), I'm stuck. I can't force Hardware::readSensor() to return 15.0f just for my test. The ClimateController is tightly coupled to the concrete TemperatureSensor class. If I run this on a build server in a chilled data center, the test might pass; on my warm laptop, it fails. That's a flaky test, and flaky tests are worse than no tests at all.
Abstracting the Problem
I need a way to lie to the ClimateController. I want to tell it, "Believe me, it's freezing in here," without actually freezing the room. The first thing I have to do is break the hard link to the hardware. I'll introduce an interface.
class ITemperatureSensor {
public:
virtual ~ITemperatureSensor() = default;
virtual float getTemperature() = 0;
};
// The real one just implements the interface now
class TemperatureSensor : public ITemperatureSensor {
public:
float getTemperature() override { return Hardware::readSensor(); }
};
// Now the controller takes the interface
class ClimateController {
ITemperatureSensor& sensor;
public:
ClimateController(ITemperatureSensor& s) : sensor(s) {}
bool checkHeatingNeeded() {
return sensor.getTemperature() < 20.0f;
}
};
Now we're getting somewhere. But I could write a "Fake" class by hand, and that gets tedious quickly once you have ten different methods to simulate. This is where Google Mock (gmock) comes in.
Making the Mock Talk
Instead of writing a whole fake class, I'll let gmock generate the implementation for me. I'll create a MockTemperatureSensor. I'm using the MOCK_METHOD macro here—it tells gmock, "Whenever this function is called, don't actually do anything; just record that it happened and return a default value."
#include "gmock/gmock.h"
class MockTemperatureSensor : public ITemperatureSensor {
public:
MOCK_METHOD(float, getTemperature, (), (override));
};
Let's try to use this in a test. I'll use ON_CALL to define what the mock should do when it's asked for the temperature.
TEST(ClimateControllerTest, TurnsOnHeaterWhenCold) {
MockTemperatureSensor mockSensor;
ClimateController controller(mockSensor);
// I'm telling the mock: "When getTemperature is called, return 15.0"
ON_CALL(mockSensor, getTemperature()).WillByDefault(testing::Return(15.0f));
EXPECT_TRUE(controller.checkHeatingNeeded());
}
This works! The test passes because the controller thinks it's 15 degrees. But there's a catch. ON_CALL is passive. It's a suggestion. If the ClimateController had a bug and never called getTemperature(), the test might still pass or fail in ways that don't actually prove the logic is correct. I don't just want the right answer; I want to ensure the controller is actually asking the sensor for the data.
Verifying the Side Effect
To move from "stubbing" (providing values) to "mocking" (verifying behavior), I'll swap ON_CALL for EXPECT_CALL. This changes the test from "If this happens, do that" to "I expect this to happen, and if it doesn't, fail the test."
TEST(ClimateControllerTest, CallsSensorExactlyOnce) {
MockTemperatureSensor mockSensor;
ClimateController controller(mockSensor);
// This will fail the test if getTemperature() is NOT called exactly once
EXPECT_CALL(mockSensor, getTemperature())
.Times(1)
.WillOnce(testing::Return(15.0f));
controller.checkHeatingNeeded();
}
I've noticed that as I build more complex mocks, I sometimes forget to add the (override) specifier in the MOCK_METHOD macro. If you do that, the compiler might not warn you if the base class interface changes, and your mock will suddenly stop being called because the signatures no longer match. Always include it.
Now I can simulate any scenario—sensor timeouts, extreme heat, or erratic readings—without ever leaving my chair or touching a piece of hardware.
📋 Practical Task
Exercise: Simulating a Payment Gateway Failure in an Order Processor
You are building an OrderProcessor class that depends on an IPaymentGateway. The processor should only mark an order as "Paid" if the gateway's processPayment method returns true. If it returns false, the order should be marked as "PaymentFailed".
Your task:
- Create the
IPaymentGatewayinterface with a methodvirtual bool processPayment(double amount) = 0;. - Create a
MockPaymentGatewayusing Google Mock. - Write a unit test for the
OrderProcessorthat usesEXPECT_CALLto simulate a failed payment (returningfalse). - Verify that the
OrderProcessorcorrectly transitions the order status to "PaymentFailed" when the mock returnsfalse.
Ensure your mock specifically verifies that processPayment was called with the correct order amount.
There are no comments for now.