Skip to main content

Section 16.8 Testing Objects

When writing unit tests for objects, we have a challenge - the testing code is generally outside of the class and thus can’t directly inspect object members. This means that we need to make sure the interface provides enough information to test the object. The easiest way to do this is to provide getters for every member variable.
Because out tests must rely on the public functions, they will be focused on testing the interface of the class. Which is actually a logical thing to do. The interface to the class is what all other code will be interacting with. And it is the interface that needs to remain consistent to avoid breaking other code.
In general, each member function (including constructors) should get one or more tests. The exception are simple getters. They will end up getting tested as part of every other test. Each test will need to start by constructing an object to test, then manipulating it, and then checking its state. Here is what a few of the tests for our Point class might look like:
TEST_CASE("Point Constructor - 2 args") {
    Point p1(3.0, 4.2);
    CHECK(p1.getX() == doctest::Approx(3.0));
    CHECK(p1.getY() == doctest::Approx(4.2));
}

TEST_CASE("Point Constructor - default") {
    Point p1;
    CHECK(p1.getX() == doctest::Approx(0.0));
    CHECK(p1.getY() == doctest::Approx(0.0)); 
}

TEST_CASE("Point shift") {
    Point p1;
    p1.shift(3.0, 4.2);
    CHECK(p1.getX() == doctest::Approx(3.0));
    CHECK(p1.getY() == doctest::Approx(4.2));
    // Test a negative shift
    p1.shift(-1.0, -2.0);
    CHECK(p1.getX() == doctest::Approx(2.0));
    CHECK(p1.getY() == doctest::Approx(2.2));
}
As always, we should stop to consider what special cases there are and ensure that the behavior for those is tested. And, if any code is conditional, we should make sure it properly handles different cases. For example, if our Point class has a getQuadrant that returned 1-4 depending on the quadrant the point was in, we would want to make sure each of the four possible answers was returned when appropriate.
Because every test will need to use a constructor and various getters, we will likely want to start by implementing and testing those in our initial development. If we were starting out to develop the point class, we would likely want to start out with something like this:
Listing 16.8.1.
Once we have that base in place, we can use incremental development and pick one function at a time to work on.

Checkpoint 16.8.1.

Examine the code below. There is a test written for a function scaleFromOrigin. Write the missing function so it passes the test cases.
Hint 1.
When scaling a figure from the origin, we simply need to multiply both the x and y coordinates of each point by the scale factor. So (3, 4.2) scaled by a factor of 2 results in (6, 8.4).
Hint 2.
Your function should be void and should take a single double or int as its parameter.
You have attempted of activities on this page.