Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TDD: Test member initialization deterministically, given undefined behavior in C++

Note: I know that active_ could be "anything" in my example. This is not what this question is about. It's about making an "undefined value" reliably fail a unit test.

Edit: Changed from "no constructor" to "empty constructor".

I'm working on a C++ class and I'm using TDD. Now I want to ensure that a bool class member is initialized properly - that a value is assigned to it in the constructor. So I write the following test (using the Google Mock/Google Test framework):

TEST(MyClass, isNotActiveUponCreation) {
    MyClass my;
    ASSERT_FALSE(my.isActive());
}

And the following class definition:

class MyClass {
public:
    // Note: Constructor doesn't initialize active_
    MyClass() {}

    bool isActive() const { return active_; }
private:
    bool active_;
};

The problem: On my machine, this test currently always passes, even though active_ is never initialized. Now we know that the value of active_ is undefined, since it's a primitive type and never initialized. So in theory, it might be true at some point, but in the end, it's impossible to know. Bottom line is, I cannot reliably test for missing initialization using this approach.

Does anybody have an idea how I might test this situation in a way that's deterministic and repeatable? Or do I have to live with it, omit this kind of test and hope that I'll never forget to initialize a boolean member, or that other tests will always catch resulting defects?

like image 999
lethal-guitar Avatar asked Feb 13 '14 09:02

lethal-guitar


1 Answers

After reading TobiMcNamobi's answer, I remembered placement new and got an idea how to solve my problem. The following test reliably fails unless I initialize active_ in the constructor:

#include <gmock/gmock.h>
#include <vector>

class MyClass {
public:
    // Note: Constructor doesn't initialize active_
    MyClass() {}

    bool isActive() const { return active_; }
private:
    bool active_;
};

TEST(MyClass, isNotActiveUponCreation) {
    // Memory with well-known content
    std::vector<char> preFilledMemory(sizeof(MyClass), 1);

    // Create a MyClass object in that memory area using placement new
    auto* myObject = new(preFilledMemory.data()) MyClass();


    ASSERT_FALSE(myObject->isActive());
    myObject->~MyClass();
}

Now I'll admit that this test is not the most readable one, and likely not immediately clear at first sight, but it works reliably and independent of any 3rd-party tools like valgrind. Is it worth the additional effort? I'm not sure. It heavily depends on MyClass internals, which will make it very brittle. Anyway, it is one way to test for correctly initialized objects in C++..

like image 181
lethal-guitar Avatar answered Sep 28 '22 10:09

lethal-guitar