SmartLogic Logo (443) 451-3001

The SmartLogic Blog

SmartLogic is a web and mobile product development studio based in Baltimore. Contact us for help building your product or visit our website to learn more about what we do.

TATFT: Test Private Methods in C++

February 16th, 2009 by

It’s very rare that I do any C++ programming these days. However, one of my oldest customers continues to utilize a C++-based optimization/statistics framework that we helped them build many years ago. The project has a wonderful purpose, and we owe quite a bit to some of the first people to trust us (thank you Sommer and Dorry!).

As a Ruby programmer, I’ve come to love test-driven programming. As such, I’ve made an effort recently to build a test-based workflow into this existing codebase (not always the easiest thing to do, applying a test-base to a large existing codebase). Today I found myself in dire need of being able to test private functions in C++. As a testament to the poor state of testing in other programming languages, many message boards/threads simply told me that I was testing the wrong thing (you should test the public API, not the private implementation). Well, needless to say, this left me a bit uncomfortable. The fact is, the majority of my code is tucked into private methods, and I’d be left with huge long-running end-to-end tests if I strictly followed this heuristic.

However, I came across one golden nugget, one of the most clever hacks I’ve seen in some time. By utilizing pre-processor directives, we can temporarily override the meaning of private and protected in C++ code, essentially aliasing it to public.

 #define protected public
 #define private   public
 #include "TheClassHeaderUnderTest.h"
 #undef protected
 #undef private

See what this is doing? We wrap the class that we’ll be testing in pre-processor directives to interpret protected and private as an alias for public, essentially loading that class (when including the header file) as entirely public. This allows me to access everything! Private methods, private variables, you name it. And now, just like in Ruby, it’s no holds barred, allowing me to poke and prod my objects without being wrapped on the wrist by the compiler.

Even better, these directives simply wrap your includes in your test files. In other words, I don’t have to change my implementation to achieve this.

A clever hack, no matter the language or technology, is a clever hack. And I absolutely love this hack.

Credit: I discovered this technique as a comment on this wiki.

  • ariels

    It is always nice to see this old C++ joke about how C programmers compile C++ using “c++ -Dprivate=public -Dprotected=public -Dclass=struct”. Even if it is somehow being seriously considered.

    You will also need to

    #define class struct

    to get this to work, of course. Which breaks templates.

  • John Trupiano

    Am I being mocked, haha? The technique worked well for me in my isolated scenario. Thanks for chiming in, and adding that extra bit of info regarding this breaking templates.

    Keep in mind my goal was simply to be able to unit test private methods.

  • brian

    #define class struct will crash and burn tons of places, especially with MSVC.

    A better solution is to adopt a convention that all class declarations must explicity use public/private labels and not ever rely on implied labeling.

    Thanx for the posting. While testing private functions has never been an issue for the code base I’m working on, it has sometimes been irritating.

    I wonder if some similar hack could be used as a way to get around declaring “friend” classes and functions, or better yet, give anonymous namespace functions in the implementation files access to the protected/private interface.

  • youchao

    it won’t link in visual studio,you can only cheat the compiler,not the linker.

  • Charles Calvert

    youchao is correct. Unless the entire class definition is in the header file, this is going to fail when the linker attempts to resolve the public versions of the private methods. The problem is that they’ll be declared as public in the compilation unit containing your tests, but private in the unit containing the class definition.

    One could work around this by using conditional compilation within the class header itself:

    #if defined(TESTING_SYMBOL)
    #define protected public
    #define private public

    // protected and private methods
    #undef protected
    #undef private

John Trupiano co-founded SmartLogic with Yair Flicker in May 2005 and was co-president through 2011. Check out his GitHub Projects or follow @jtrupiano on Twitter.

John Trupiano's posts