Search code examples
c++googletest

How to define variables in Googletest fixtures when they do not have a default constructor?


I have the following


#include <semsim/Subject.h>
#include <semsim/Triple.h>
#include "gtest/gtest.h"

class TripleTests : public ::testing::Test {
public:

    std::string subject_str;
    semsim::Subject subject;

    void SetUp() override {
        subject_str = "./MyModel#metaid_0";
        subject = semsim::Subject(subject_str);
    }
};

TEST_F(TripleTests, TestSubjectMetaId) { // this line causes the error
    std::cout << subject << std::endl;
}

In order to define variables (for later use in TEST_F functions), they have to be created in the class scope and then filled with a value in the SetUp method. This is because I cannot pass subject_str to the Subject at the class level. However, if you instantiate a variable at the class level, it uses the default constructor, and my class does not have (nor need) one. Here's the complaint from my IDE:

Call to implicitly-deleted default constructor of 'TripleTests' because field 'subject' has no default constructor

Therefore my question: without needing to define a default constructor, how would I create a subject object inside the TripleTest class such that it can be used in TEST_F functions? Or is it necessary to default constructor in Suject just so I can create one in a test fixture?

For reference, the Subject header looks like this:

    class Subject {
    private:
        std::string metaId;

    public:

        explicit Subject(std::string metaId) : metaId(std::move(metaId)) {};

        const std::string &getMetaId() const;

        bool operator==(const Subject &rhs) const;

        bool operator!=(const Subject &rhs) const;

        friend std::ostream &operator<<(std::ostream &os, const Subject &subject);
    };

}

Edit

The answer by @Tomasz


class TripleTests : public ::testing::Test {
public:

    std::string subject_str;
    semsim::Subject subject;
    // alternative 1
    TripleTests()  {
        this->subject_str = "./MyModel#metaid_0";
        semsim::Subject s(subject_str);
        this->subject = s;
    }

    // alternative 2
    TripleTests()  {
        this->subject_str = "./MyModel#metaid_0";
        this->subject = semsim::Subject(subject_str);
    }

results in

Constructor for 'TripleTests' must explicitly initialize the member 'subject' which does not have a default constructor. Isn't the line `this->subject = s` initialising the member `subject`? 

Solution

  • You have to use fixture's constructor instead of SetUp() to initialize members in intializer list:

    class TripleTests : public ::testing::Test {
    public:
    
        std::string subject_str;
        semsim::Subject subject;
    
        TripleTests() 
            : subject_str("./MyModel#metaid_0")
            , subject(subject_str)
        {
        }
    };