Specify constructor arguments for a Google test Fixture - c++

With Google test I want to specify a Test fixture for use in different test cases.
The fixture shall allocate and deallocate objects of the class TheClass and its data management class TheClassData, where the data management class requires the name of a datafile.
For the different tests, the file name should vary.
I defined the following Fixture:
class TheClassTest : public ::testing::Test {
protected:
TheClassTest(std::string filename) : datafile(filename) {}
virtual ~TheClassTest() {}
virtual void SetUp() {
data = new TheClassData(datafile);
tc = new TheClass(data);
}
virtual void TearDown() {
delete tc;
delete data;
}
std::string datafile;
TheClassData* data;
TheClass* tc;
};
Now, different tests should use the fixture with different file names.
Imagine this as setting up a test environment.
The question: How can I specify the filename from a test, i.e. how to call a non-default constructor of a fixture?
I found things like ::testing::TestWithParam<T> and TEST_P, which doesn't help, as I don't want to run one test with different values, but different tests with one fixture.

As suggested by another user, you cannot achieve what you want
by instantiating a fixture using a non-default constructor. However,
there are other ways. Simply overload the SetUp function and
call that version explicitly in the tests:
class TheClassTest : public ::testing::Test {
protected:
TheClassTest() {}
virtual ~TheClassTest() {}
void SetUp(const std::string &filename) {
data = new TheClassData(filename);
tc = new TheClass(data);
}
virtual void TearDown() {
delete tc;
delete data;
}
TheClassData* data;
TheClass* tc;
};
Now in the test simply use this overload to set up filename:
TEST_F(TheClassTest, MyTestCaseName)
{
SetUp("my_filename_for_this_test_case");
...
}
The parameterless TearDown will automatically clean up when
the test is complete.

Use the current class as a base class for your fixtures:
class TheClassTestBase : public ::testing::Test {
protected:
TheClassTestBase(std::string filename) : datafile(filename) {}
...
};
For every specific filename - use derived fixture:
class TheClassTestForFooTxt : public TheClassTestBase {
protected:
TheClassTestForFooTxt() : TheClassTestBase ("foo.txt") {}
};
However this is extra step needed for every set of parameters - so you can try to use templates or macros to get it done with less effort. Like:
template <typename ClassTestTag>
struct ClassTestParams
{
static std::string filename;
};
template<typename ClassTestTag>
class TheClassTest : public TheClassTestBase {
protected:
TheClassTest() : TheClassTestBase (ClassTestParams<ClassTestTag>::filename) {}
};
Then - for every set of parameters - do that:
class FooTxtTag {};
template <> std::string ClassTestParams<FooTxtTag>::value = "foo.txt";
using TheClassTestForFooTxt = TheClassTest<FooTxtTag>;
TEST_F(TheClassTestForFooTxt, xxxx) {}
However - in your specific case - I would also try GoogleTest:type-parameterized-tests.

Another great way to deal with this is to just extend your fixture and in the extended class supply a new default constructor which calls through to the old one with the arguments you require. For example:
struct MySpecializedTestFixture : public GenericTestFixture
{
MySpecializedTestFixture() : GenericTestFixture("a thing", "another thing") {}
};
TEST_F(MySpecializedTestFixture, FancyTest)
{
// Use the thing environment and make some assertions.
}

If you overload the SetUp method as suggested here, and you want to ensure that you remember to use the overloaded SetUp, you can use an assertion in the TearDown method.
class my_fixture : public ::testing::Test
{
protected:
bool SETUP_HIT_FLAG = false;
void SetUp(double parameter)
{
...
SETUP_HIT_FLAG = true;
}
void TearDown() override
{
assert(SETUP_HIT_FLAG && "You forgot to call SetUp with your parameter!");
}
};

Another way using templates:
template<int N>
class Fixture : public ::testing::Test { ... }
using FixtureForTest = Fixture<1000>;
TEST_F(FixtureForTest, test) { ... }

For this specific case, I feel it is much easier to get rid of the test fixture altogether. The SetUp function can instead be replaced with a helper function that instantiates the class with the required file name. This permits the use of TEST instead of TEST_P or TEST_F. Now each test case is a standalone test which creates its own test class instances with the helper function or directly in the body of the test case.
For example:
using namespace testing;
TEST(FooClassTest, testCase1)
{
FooClass fooInstance("File_name_for_testCase1.txt");
/* The test case body*/
delete fooInstance;
}

Related

gmock: force mocking out of a class method without defining and referencing a mock class?

the normal pattern of gmock testing is
class MyMockClass : public MyRealClass {
/// swap out behavior of an existng method
MOCK_method(some_method .....);
}
TEST() {
MyMockClass mock;
EXPECT_CALLED(mock.some_method);
/// ******* here I have to explicitly pass in the mock obj into the system
MyConsumerClass myconsumer(mock);
myconsumer.do_something_to_trigger_mock__some_method();
}
in the above "****" line I have to explicitly pass in a mock obj into the system, i.e. compose my consumer obj with a mock obj. But now I face an existing consumer class impl, its constructor does not allow passing in the dependency objects; in fact I can probably argue that it's impossible to list all the dependency objects in the ctor of a consumer class; more importantly, my real case is that the consumer class to be tested sits several levels above the mock obj:
class MyConsumerClass {
private:
MyHelperClass helper
public:
void trigger() {
helper.trigger_again();
}
}
class MyHelperClass {
BottomClass bottom;
public:
void trigger_again() {
bottom.do_something();
}
}
class BottomClass {
public :
void do_something();
}
in this case, in our unit test, we can only instantiate the top level MyConsumerClass, and I was hoping to verify that when I call myconsumer.trigger(), I could verify that the BottomClass.do_something() is called, possibly also verifying that it's called with a specific argument. But the above class hierarchy is written so that I can not pass in a mock BottomClass obj from the top level.
in jmock or jmockit, I remember it's possible to globally wipe out the behavior of BottomClass.do_something(), without referring to a specific mock obj, i.e. "static mocking", as they are called in jmockit. is it possible to do something like that in gmock (c++)? thanks
Converting the comment to an answer:
I can think of two things:
Why don't you test your classes separately? For example, write a separate test for MyHelperClass.
If dependency injection doesn't work for you, GMock allows you to do static mocking by templatizing your classes: Convert your classes to templates, then instantiate the template with real classes for production and with mock classes for testing. See here for an example.
In your case, your code could be rewritten to something like this:
//-----------------------------------------------------------------------------
// Real classes used in production
//-----------------------------------------------------------------------------
class BottomClass {
public:
void do_something();
};
//-----------------------------------------------------------------------------
// Templatized classes used in test or production
//-----------------------------------------------------------------------------
template <class BType>
class MyHelperClass {
public:
BType bottom;
public:
void trigger_again() { bottom.do_something(); }
};
template <class BType, template <typename> class HType>
class MyConsumerClass {
public:
HType<BType> helper;
public:
void trigger() { helper.trigger_again(); }
};
//-----------------------------------------------------------------------------
// Mocked classes used in test
//-----------------------------------------------------------------------------
class MockedBottomClass {
public:
MOCK_METHOD(void, do_something, (), ());
};
TEST(BottomClassTest, Test1) {
MyConsumerClass<MockedBottomClass, MyHelperClass> mock;
EXPECT_CALL(mock.helper.bottom, do_something());
mock.trigger();
}
I had to convert some of your private members to public members for the test to work.
Live example here: https://godbolt.org/z/qc3chdxKz

C++ Overwrite initializer list in unit test

I have some C++ code like this that I want to unit test:
class Example
{
private:
ExpensiveObject expensiveObject;
public:
Example() : expensiveObject() {
... constructor code
}
methodA() {
... some code
}
}
To write a unit test for methodA I need to create an instance of Example. The problem is that I don't want to initialize expensiveObject, I would want to set it to null in my unit test (I am using Google Test). Is there a way to do it?
expensiveObject cannot be assigned null. What you might want is to have a smart pointer to ExpensiveObject, and have multiple constructors or better you want to inject your dependencies.
class Example
{
private:
std::shared_ptr<ExpensiveObject> expensiveObject;
public:
Example(std::shared_ptr<ExpensiveObject> ptr) : expensiveObject(ptr) {
//... constructor code
}
methodA() {
//... some code
}
}
Now you can test it for null scenarios as well
Example ex{nullptr};
ex.methodA();
I can't think of any way to do this without slightly modifying the definition of the Example class. However, if you can tolerate to do this, there are several ways to do this: dependency injection using pointers as the other answer mentioned, or templatizing the class as shown below:
// Used for production.
class ExpensiveObject {
// Expensive stuff here
};
// Only used for testing.
class CheapObject {
// Cheap stuff here
};
// Instantiate with ExpensiveObject for production and with CheapObject for
// testing.
template <class T>
class Example {
private:
T expensiveObject;
public:
Example() : expensiveObject() {}
int methodA() { return 1; }
};
TEST(Example, Test1) {
// CheapObject is used for testing.
Example<CheapObject> example;
EXPECT_EQ(example.methodA(), 1);
}
Live example: https://godbolt.org/z/7e1rhWY4b

GTest - how to prepare data for multiple usage via SetUp method?

I am trying to run some google tests, and I have quite a lot of code to repeat in each test fixture, so I want to make the code as brief as possible, and I would like to use the SetUp method of the child class of Testing::test parent class, but the TEST_F fixtures do not recognize the variables from SetUp
This is the simplest example I can come up with:
class FooTest: public testing::Test
{
protected:
virtual void SetUp() // using void SetUp() override does not help
{
int FooVar = 911;
}
virtual void TearDown()
{
}
};
TEST_F(FooTest, SampleTest)
{
// FooTest::SetUp(); // This does not help as well
EXPECT_EQ(911, FooVar);
}
When I try to compile this code it shows an error that FooVar was not declared in this scope. How can I fix it?
Thank you very much for any help.
FooVar is a local variable inside the SetUp method. If you want to use it in the test fixtures, it needs to be a class member:
class FooTest: public testing::Test
{
protected:
int FooVar;
virtual void SetUp() override
{
this.FooVar = 911;
}
};
In this example, if you are only setting integral types, should just make them const member variables.

Why does GMOCK object not return values set by EXPECT_CALL in dependency injection

I have the following object that I want to mock:
class Esc {
public:
Esc() = default;
virtual ~Esc() {}
virtual int GetMaxPulseDurationInMicroSeconds() const noexcept{
return 100;
}
};
I wrote this mock:
class MockEsc : public Esc {
public:
MockEsc(){}
MockEsc(const MockEsc&){}
MOCK_METHOD(int, GetMaxPulseDurationInMicroSeconds, (), (const, noexcept, override));
};
And this is the unit under test which calls the aforementioned Esc.GetMaxPulseDurationInMicroSeconds() method
class LeTodar2204{
public:
LeTodar2204() = delete;
explicit LeTodar2204(std::unique_ptr<Esc> esc) : esc_(std::move(esc)){}
int CallingMethod(){
int a = esc_->GetMaxPulseDurationInMicroSeconds();
return a;
}
private:
std::unique_ptr<Esc> esc_;
In the SetUp of my testfixture I want to set my mock to return a 1 and inject it into the unit under test.
class Letodar2204Tests : public ::testing::Test {
protected:
Letodar2204Tests() {}
virtual void SetUp() {
EXPECT_CALL(esc_, GetMaxPulseDurationInMicroSeconds()).WillOnce(::testing::Return(1));
unit_under_test_ = std::make_unique<propulsion::LeTodar2204>(std::make_unique<MockEsc>(esc_));
}
MockEsc esc_;
std::unique_ptr<propulsion::LeTodar2204> unit_under_test_;
};
Now in the test I call the method that should call the mocked method, but GetMaxPulseDurationInMicroSeconds of my mocked object only returns 0 (aka the default value) and warns me about the uninteresting function call.
This is the test
TEST_F(Letodar2204Tests, get_pulse_duration) {
EXPECT_CALL(esc_, GetMaxPulseDurationInMicroSeconds()).WillOnce(::testing::Return(1));
auto duration = unit_under_test_->CallingMethod();
ASSERT_EQ(duration, 1);
}
What am I missing?
Because you are effectively assigning expectation to an object which you'll be copying anyway. esc_ default ctor is going to be called once Letodar2204Tests is instantiated. Now, in SetUp you assign an expectation on class' field esc_, and then, basing on esc_ create a brand new object (on the heap, using make_unique) using its copy-ctor. Expectations are not going to be magically copied as well. I believe you should store an unique_ptr<MockEsc> esc_ as a class' field, instantiate it on heap within SetUp and inject to LeTodar:
class Letodar2204Tests : public ::testing::Test {
protected:
Letodar2204Tests() {}
virtual void SetUp() {
esc_ = std::make_unique<MockEsc>();
EXPECT_CALL(*esc_, GetMaxPulseDurationInMicroSeconds()).WillOnce(::testing::Return(1));
unit_under_test_ = std::make_unique<propulsion::LeTodar2204>(esc_);
}
std::unique_ptr<MockEsc> esc_;
std::unique_ptr<propulsion::LeTodar2204> unit_under_test_;
};
Here, you are implicitly calling copy-ctor: std::make_unique<MockEsc>(esc_)
You could do a simple test: mark copy ctor in MockEsc 'deleted' and you'll see that your project no longer compiles (at least it shouldn't be :D)

How to use mocks with a test fixture in GMock?

I have a test fixture in my tests so I don't have to instantiate objects of my class repeatedly, but I'm not sure how to use mocks with it. To put it simply, this is how the class is defined:
class Class1 {
public:
Class1(std::shared_ptr<Class2> class_two);
void doThisThing() { doThatThing(); }
}
class Class2 {
public:
Class2(Class3* class3_ptr);
int doThatThing();
}
(class 1 is constructed using a shared pointer to class 2. Class 2 is constructed with a pointer to class 3. Class 1 calls on a function "doThisThing" which calls Class 2's function doThatThing.)
I need to create a mock for doThatThing() (and the rest of Class2's functions), but can't figure out how to pass the mock object to Class 1. Here is what I have so far in my testing code:
class TestClass1 : public ::testing::Test {
TestClass1(){
//Construct instance of Class1 and store as member variable
std::shared_ptr<Class3> class_three = std::make_shared<Class3>();
std::shared_ptr<Class2> class_two = std::make_shared<Class2>((Class3*)class_three.get());
class_one = new Class1(class_two);
};
Class1* class_one;
}
MockClass2 : public Class2 {
MOCK_METHOD0(doThatThing, int());
}
TEST_F(TestClass1, doThatThingTest){
MockClass2 mockObj;
**THIS IS WHERE I'M STUCK. How do I get that mockObj into my TestClass1 Fixture? As of now, it is calling the actual function, not the mock***
class_one->doThatThing();
EXPECT_CALL(mockObj, doThatThing());
}
I had to abstract and simplify the actual code, so I hope the above makes sense.
Assuming that your MockClass2 works, you should try something like the following:
Here you should override the functions SetUp that is called right before every call of a test function to prepare your test data. And override TearDown that is called after every call of a test function to clean up test data.
struct TestClass1 : public ::testing::Test
{
void SetUp() override
{
class_two_mock = std::make_shared<MockClass2>();
class_one = std::make_unique<Class1>(class_two_mock);
}
void TearDown() override
{
class_one.reset();
class_two_mock.reset();
}
std::shared_ptr<MockClass2> class_two_mock
std::unique_ptr<Class1> class_one;
};
In the test function you must declare your expectations before something is executed.
TEST_F(TestClass1, doThatThingTest)
{
EXPECT_CALL(*class_two_mock, doThatThing());
class_one->doThatThing();
}
You may need an interface for Class2. The code here is not tested.