12

I've been racking my brain trying to think of the best way to access a protected member function from some test code in C++, here's my problem:

//in Foo.h 
Class Foo
{
protected:
    void DoSomething(Data data);
}

//in Blah.h
Class Blah
{
public:
    Foo foo;
    Data data; 
};

//in test code...
Blah blah;
blah.foo.DoSomething(blah.data); // Here's my problem!

Some possible solutions so far:

  • Make the test code class a friend of Foo, but this pollutes Foo with test code
  • Make DoSomething a public function
  • I've looked at creating a test wrapper for Foo, as suggested in this post, however this won't work as Blah contains the instance of Foo.

    All advice/insight/opinions are most welcome!

    Thanks

  • Community
    • 1
    • 1
    sarah
    • 145
    • 1
    • 2
    • 6
    • 5
      why do you want to test the protected method? I believe you should test the public interfaces of the class and leave the internal implementation to the class itself. – Naveen Nov 12 '09 at 17:34
    • 3
      @AraK, i'm sorry to see you deleted your answer. It was nearly right, but you should have done `&test::DoSomething` instead of `&Foo::DoSomething` - that's the important thing in that trick, because it makes access checking go fine. Since you were first to answer tell me if you wanna undelete your answer and i will remove my answer below! – Johannes Schaub - litb Nov 12 '09 at 20:43
    • Duplicate? http://stackoverflow.com/questions/1127616/what-is-the-best-way-to-unit-test-a-protected-method-in-c – Rob Kennedy Nov 12 '09 at 22:21
    • Umm why wouldn't you just create a derived class? Every answer I see here undermines the entire purpose of object orientation. Inheritance exists for a reason! – arkon Mar 26 '13 at 00:44

    8 Answers8

    18

    There is a way which is completely allowed by the Standard.

    //in Foo.h 
    class Foo
    {
    protected:
        void DoSomething(Data data);
    };
    
    //in Blah.h
    class Blah
    {
    public:
        Foo foo;
        Data data; 
    };
    
    //in test code...
    struct FooExposer : Foo {
      using Foo::DoSomething;
    };
    
    Blah blah;
    (blah.foo.*&FooExposer::DoSomething)(blah.data);
    

    Read the Hidden features of C++ entry for an explanation.


    You may write a macro for your convenience (the parenthesis are there so that you can use this macro also for types that have a comma, like vector<pair<A, B>>):

    #define ACCESS(A, M, N) struct N : get_a1<void A>::type { using get_a1<void A>::type::M; }
    
    template<typename T> struct get_a1;
    template<typename R, typename A1> struct get_a1<R(A1)> { typedef A1 type; };
    

    The matter now becomes

    ACCESS((Foo), DoSomething, GetDoSomething);
    Blah blah;
    (blah.foo.*&GetDoSomething::DoSomething)(blah.data);
    
    Community
    • 1
    • 1
    Johannes Schaub - litb
    • 496,577
    • 130
    • 894
    • 1,212
    • Fine indeed. A pity it would not work with `private` methods. – Matthieu M. Nov 13 '09 at 08:23
    • For those that want to do this a lot, grab the templates from above, then add: #define ACCESS(A, M) struct M##_struct : get_a1::type { using get_a1::type::M; } #define CALL(B, M) ((B).*&M##_struct::M) To use this: do ACCESS((Foo), DoSomething) at the top of your program. Then do CALL(foo, DoSomething)(arg1, arg2) to call the protected method. – thepenguin77 Oct 16 '16 at 23:36
    • [this](http://ideone.com/keDOxd) fails in VS2015 update 3: `error C2440: '.*': cannot convert from 'A *' to 'B *'`, only for member functions, compiles fine for member variables – Andriy Tylychko Feb 07 '17 at 11:44
    • actually, it doesn't compile also on VS2012 and VS2013, is this VC++ compiler non conformance to C++ standard? – Andriy Tylychko Feb 07 '17 at 11:56
    • @AndyT I have no idea. I suspect that it's non conformance. But it's too long since I've written the code, so I forgot. – Johannes Schaub - litb Feb 07 '17 at 16:01
    8

    Ok, since you said it is only a test code I am going to suggest something seriously hacky but would work:

    struct tc : protected Foo
    {
        tc(Foo *foo, Data& data)
        {
            ((tc*)foo)->DoSomething(data);
        }
    };
    
    Blah blah;
    tc t(&blah.foo, blah.data);
    
    Murali VP
    • 6,198
    • 4
    • 28
    • 36
    7

    On the one hand, don't do that.

    On the other hand, here's a gamble:

    #define protected public
    #include "foo.h"
    #undef protected
    

    8-)

    But seriously, why is DoSomething() protected? Probably because calling it from external code can break something. In which case, you shouldn't be calling it from your tests.

    RichieHindle
    • 272,464
    • 47
    • 358
    • 399
    • Wouldn't friending be a better way to go here, if you absolutely have to test protected members (which I agree, you shouldn't be doing). – Dominic Rodger Nov 12 '09 at 17:37
    • @Dominic: Yes, but @sarah explicitly doesn't want to use `friend`. – RichieHindle Nov 12 '09 at 17:42
    • 1
      And this hack works (sometimes) when you have the header and a library, but not source, for the classes you want to exercise. – Don Wakefield Nov 12 '09 at 18:13
    • (to be fair, you do not recommend this, so this comment is not against your answer, but just against that technique). This probably works when "foo.h" is actually just a file with one class and nothing else, so you have complete control over this. But I would not do this, as anything that header includes indirectly will be affected too. Probably a whole other piece of code. It could cause a different ABI interface which can cause strange effects - you never know what the compiler does internally - maybe it orders member by their accessibility, or something. – Johannes Schaub - litb Nov 12 '09 at 21:13
    • @RichieHindle - I'm going to reassess whether the function needs to be protected in the first place. Thanks for the advice :) – sarah Nov 19 '09 at 16:02
    3

    I've done

    class Foo
    {
    protected:
        void DoSomething(Data data);
    public:
        #ifdef TEST
        void testDoSomething(Data data);
        #endif
    }
    

    Then compile your unit tests with g++ -D TEST.

    Dan Hook
    • 6,769
    • 7
    • 35
    • 52
    3

    Rather than ifdefing private to public, consider ifdefing friendship, or better yet think if that function really needs to belong to that class, maybe it would suffice to have something in a named/unnamed namespace in a cpp, and then declared in a test project.

    Anyway, check this link, maybe your testing framework would provide similar functionality.

    EDIT: Did you consider inheriting your test class from your real class?

    Vadim Kotov
    • 8,084
    • 8
    • 48
    • 62
    Dmitry
    • 6,590
    • 2
    • 26
    • 19
    2

    You could use inheritance with forwarding functions:

    class Foo
    {
    protected:
        void DoSomething(Data data);
    }
    
    class test_Foo : public Foo
    {
    public:
        void testDoSomething(Data data)
        {
            DoSomething(data);
        }
    }
    
    mocj
    • 1,456
    • 1
    • 9
    • 9
    • 1
      You'd probably want to combine this with Dependency Injection so you can replace the Foo in Blah with a test_Foo instance. – Mark Bessey Nov 12 '09 at 20:12
    2

    Use wrapper as follows:

    // Foo.h unchanged
    
    // Blah.h unchanged
    
    // test code
    class FooTest : public Foo { friend void test(); }; // make friends
    
    void test()
    {
        Blah blah;
        static_cast<FooTest*>(&blah.foo)->DoSomething(blah.data); // Here's no problem!    
    }
    
    Kirill V. Lyadvinsky
    • 97,037
    • 24
    • 136
    • 212
    1

    If it is strictly test code, you could do...

    #define protected public
    #include "Foo.h"
    
    // test code
    
    #undef protected
    
    lyricat
    • 1,988
    • 2
    • 12
    • 20