Skip to Content
Course content

129: Unit Testing with Google Test

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've been working on a small utility class called TemperatureConverter. It’s simple enough—converting Celsius to Fahrenheit and Kelvin—but I’ve found myself falling into a bad habit: writing a main() function, printing a few values to the console, and squinting at the screen to see if the numbers look "about right."

// My current "testing" method
int main() {
    TemperatureConverter tc;
    std::cout << "C to F (100): " << tc.celsiusToFahrenheit(100) << std::endl; 
    // I'm just hoping this prints 212...
    return 0;
}

The pain of manual verification

The problem is that as soon as I add a new feature—say, a check to ensure we don't go below absolute zero—I have to manually re-check every single previous print statement. It's tedious, and frankly, it's where bugs slip through. I need a way to define what "correct" looks like once, and then just hit a button to verify it every time I change the code.

That's where Google Test (gTest) comes in. I've already linked the library to my project, so I don't want to bore you with the CMake boilerplate. Instead, let's just start writing a test. I'll create a new file specifically for tests so I don't clutter my production code.

#include 
#include "TemperatureConverter.h"

TEST(TempConverterTest, HandlesBoilingPoint) {
    TemperatureConverter tc;
    EXPECT_EQ(tc.celsiusToFahrenheit(100.0), 212.0);
}

I'm using the TEST() macro here. The first argument is the "Test Suite" (a group of related tests) and the second is the specific "Test Case." When I run this, gTest tells me it passed. Great. But let's try something that actually fails to see how it behaves.

When the math doesn't quite line up

I'll add a test for the Kelvin conversion. I know that 0°C is 273.15K.

TEST(TempConverterTest, HandlesFreezingPointKelvin) {
    TemperatureConverter tc;
    EXPECT_EQ(tc.celsiusToKelvin(0.0), 273.15);
}

I run the tests, and... it fails. Wait, what? I checked my math, and the function is definitely returning 273.15. The error message says something like Expected: 273.15, Actual: 273.15000000000003. Ah, the classic floating-point precision trap. I forgot that EXPECT_EQ does a strict equality check, which is almost always a mistake with double or float.

I need to tell gTest, "These numbers are close enough." I'll swap EXPECT_EQ for EXPECT_NEAR, which lets me specify a tolerance.

TEST(TempConverterTest, HandlesFreezingPointKelvin) {
    TemperatureConverter tc;
    // 0.001 is plenty of precision for a thermometer
    EXPECT_NEAR(tc.celsiusToKelvin(0.0), 273.15, 0.001);
}

That passes. Now we're actually testing the logic, not the quirks of IEEE 754 floating-point representation.

Catching the edge cases

Now for the real reason I'm doing this. I want to make sure my converter throws an exception if someone tries to set a temperature below absolute zero (-273.15°C). I'll add a guard clause to my actual TemperatureConverter class first:

double celsiusToFahrenheit(double c) {
    if (c < -273.15) throw std::invalid_argument("Below absolute zero!");
    return (c * 9.0 / 5.0) + 32.0;
}

Now, how do I test that an exception actually happens? I can't just call the function, or the test runner will crash. gTest has a specific macro for this: EXPECT_THROW.

TEST(TempConverterTest, ThrowsOnAbsoluteZero) {
    TemperatureConverter tc;
    EXPECT_THROW(tc.celsiusToFahrenheit(-300.0), std::invalid_argument);
}

I love this part of the process. Instead of me manually passing -300 into the program and watching it crash to see if the error message is correct, I've codified the failure. If some future version of me (or a teammate) accidentally removes that guard clause to "optimize" the code, this test will immediately turn red and yell at us.

  • EXPECT_EQ: Use for integers or booleans.
  • EXPECT_NEAR: Use for floating point numbers.
  • EXPECT_THROW: Use to verify your error handling works.



📋 Practical Task

Implementing a Robust StockPortfolio Validator

You are building a StockPortfolio class that tracks the total value of a user's holdings. The class has a method double calculateTotalValue(double shares, double pricePerShare).

Your task is to write a Google Test suite that ensures the following requirements are met:

  • Positive Calculation: Verify that 10 shares at $150.50 equals $1505.00. (Use EXPECT_NEAR).
  • Zero Value: Verify that 0 shares results in a total value of 0.0.
  • Input Validation: The method should throw a std::domain_error if either the shares or pricePerShare is negative, as you cannot have negative shares or a negative stock price.

Write the StockPortfolio implementation and the corresponding gTest cases to prove the logic is sound.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.