23

How do I unit test a protected method in C++?

In Java, I'd either create the test class in the same package as the class under test or create an anonymous subclass that exposes the method I need in my test class, but neither of those methods are available to me in C++.

I am testing an unmanaged C++ class using NUnit.

Kevin Reid
  • 37,492
  • 13
  • 80
  • 108
Alex B
  • 24,678
  • 14
  • 64
  • 87
  • Are you using GenTestAsm-http://www.codeproject.com/KB/applications/GenTestAsmBase.aspx? Or how else are you running unmanaged C++ code from NUNit (.NET)? – RichardOD Jul 14 '09 at 20:02

6 Answers6

33

Assuming you mean a protected method of a publicly-accessible class:

In the test code, define a derived class of the class under test (either directly, or from one of its derived classes). Add accessors for the protected members, or perform tests within your derived class . "protected" access control really isn't very scary in C++: it requires no co-operation from the base class to "crack into" it. So it's best not to introduce any "test code" into the base class, not even a friend declaration:

// in realclass.h
class RealClass {
    protected:
    int foo(int a) { return a+1; }
};

// in test code
#include "realclass.h"
class Test : public RealClass {
    public:
    int wrapfoo(int a) { return foo(a); }
    void testfoo(int input, int expected) {
        assert(foo(input) == expected);
    }
};

Test blah;
assert(blah.wrapfoo(1) == 2);
blah.testfoo(E_TO_THE_I_PI, 0);
Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • This is the true object oriented solution to this problem. Inheritance exists for a reason! – arkon Mar 26 '13 at 00:52
20

You can also use using keyword to expose public block (using .

// in realclass.h
class RealClass {
    protected:
    int foo(int a) { return a+1; }
    int foo(string a) { return a.length(); } // Overload works too
    template<class T> int foo(const T& a) { return 1; } // Templates work too
};

// in test code
#include "realclass.h"
class RealClassExposed : public RealClass {
    public:
        using RealClass::foo;
};

RealClassExposed blah;
assert(blah.foo(1) == 2);
assert(blah.foo("test") == 4);
assert(blah.foo(blah) == 1);

See: http://en.cppreference.com/w/cpp/language/using_declaration

KrisTC
  • 551
  • 5
  • 5
2

I use CxxTest and have the CxxTest derive from the class that contains the protected member function. If you're still searching around for your favorite C++ Unit Testing framework, take a look at this article.

Pete
  • 10,310
  • 7
  • 53
  • 59
1

Declare a friend class MyClass_UnitTest; in your MyClass. You can then define MyClass_UnitTest elsewhere in your unit test program that has full access to MyClass internals, but you don't have to provide an implementation in your release application. See CppUnit documentation for a good example of how this is done.

Rob K
  • 8,757
  • 2
  • 32
  • 36
  • 2
    Friend classes are __not__ your friend. – arkon Mar 26 '13 at 00:50
  • 1
    Then nothing is your friend. Every feature of every language can be misused and abused. Just because idiots misuse the feature doesn't mean I should never use it for its proper purpose. – Rob K Mar 26 '13 at 14:15
  • Agreed, but some features are easier to abuse than others. More often than not, I see friend functions used to circumvent encapsulation. – arkon Mar 26 '13 at 14:45
1

There's a simple solution in C++ using #define. Just wrap the include of your "ClassUnderTest" like this:

#define protected public
 #define private   public
    #include <ClassUnderTest.hpp>
 #undef protected
#undef private

Credit goes to this article and RonFox

Langley
  • 499
  • 6
  • 12
  • 2
    In response to the -1... I know in "theory" you should be testing the public interface. However, in practice during the development cycle this can be an invaluable trick. My advice... use it judiciously. – Langley Dec 23 '15 at 12:28
-1

Consider a public, possibly static 'unit test' function.

Ugly, but better than the alternatives I can think of using macros or friends or such.

Will
  • 73,905
  • 40
  • 169
  • 246