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?
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++..
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With