Testing protected member with googletest
Asked Answered
O

4

10

I'm confused regarding inheritance when googletesting. I have a class A that has protected attributes. If I want to access those i have to extend that class, but at the same time i also need to extend public ::testing::Test for the sole purpose of gtest.

What is the most elegant solution to this problem? Also I'm trying to avoid #define protected public

Olag answered 13/10, 2014 at 9:51 Comment(0)
E
6

There is a FRIEND_TEST declaration, which is used in the header of tested class. Basically it defines the test as a friend of the class. In my use case, we disable all test includes when compiling in RELEASE mode, so it doesn't do any harm the real executable.

Have a look at this

Evangelinaevangeline answered 13/10, 2014 at 10:1 Comment(3)
just what i needed, tnx :)Olag
The link to the documentation has moved here: github.com/google/googletest/blob/master/googletest/docs/…Pimentel
New location is here.Slipper
K
25

To avoid leaving traces of tests in the tested class use multiple-inheritance with a fixture:

class ToBeTested
{
protected:
    bool SensitiveInternal(int p1, int p2); // Still needs testing
}

// Google-test:
class ToBeTestedFixture : public ToBeTested, public testing::Test
{
   // Empty - bridge to protected members for unit-testing
}

TEST_F(ToBeTestedFixture, TestSensitive)
{
    ASSERT_TRUE(SensitiveInternal(1, 1));
    ASSERT_FALSE(SensitiveInternal(-1, -1));
}
Kristykristyn answered 14/8, 2015 at 13:26 Comment(1)
Got stuck here because this only seems to work if ToBeTested only has a no-arg constructor. In my case, I have an arg'd constructor.Roundtheclock
E
6

There is a FRIEND_TEST declaration, which is used in the header of tested class. Basically it defines the test as a friend of the class. In my use case, we disable all test includes when compiling in RELEASE mode, so it doesn't do any harm the real executable.

Have a look at this

Evangelinaevangeline answered 13/10, 2014 at 10:1 Comment(3)
just what i needed, tnx :)Olag
The link to the documentation has moved here: github.com/google/googletest/blob/master/googletest/docs/…Pimentel
New location is here.Slipper
L
1

I ended up using a combination of Rene's and lisu's answers to solve the problem of non-default constructors:

class ToBeTested
{
public:
    ToBeTested() = delete;

    ToBeTested(int p): p1(p) {}

protected:
    bool SensitiveInternal(int p2) {return p1 == p2;}// Still needs testing

    const int p1;
};

// Stub to bridge the acess restrictions:
class ToBeTestedStub : public ToBeTested
{
public:
    ToBeTestedStub(int p):ToBeTested(p) {}
    FRIEND_TEST(ToBeTestedFixture, TestSensitive);
};


// Google-test:
class ToBeTestedFixture : public testing::Test
{
public:
    void SetUp() override
    {
        stub = std::make_unique<ToBeTestedStub>(1);
    }

    // Using a pointer so we can instantiate the stub in the SetUp method.
    std::unique_ptr<ToBeTestedStub> stub;
};

TEST_F(ToBeTestedFixture, TestSensitive)
{
    ASSERT_TRUE(stub->SensitiveInternal(1));
    ASSERT_FALSE(stub->SensitiveInternal(2));
}

An alternative is shown in this answer:

// Stub to bridge the acess restrictions:
class ToBeTestedStub : public ToBeTested
{
public:
    ToBeTestedStub(int p):ToBeTested(p) {}
    using ToBeTested::SensitiveInternal;
};
Lucite answered 2/11, 2023 at 15:41 Comment(0)
L
0

I suggest to implement a stub class B which inherits the base class A. Class B then provides all the protected methods of class A as public. That way you can instanciate a object of the stub object and take it under test as usual.

class Base
{
 public:
  Base(int x);
  virtual ~Base()=default;
 
 protected:
  bool myMethod();
}

class stubBase : public Base
{
 public:
  stubBase(int x) : Base(x){}
  bool myMethod(){ Base::myMethod(); }
}

TEST(Base, myMethod)
{
  stubBase stub(1);
  EXPECT_TRUE(stub.myMethod());
}
Lithographer answered 6/7, 2023 at 11:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.