开发者

How to access private class fields from a test using UnitTest++?

I'm facing a nuisance when coding my unit tests using UnitTest++. I'm wondering how to access private member class fields in a clean way (or maybe any way...)

By now, I have a solution to access protected members using a class fixture deriving from the class under test. The following code shows the idea:

struct MyFixture : ClassUnderTest { };

TEST_FIXTURE(MyFixture, OneTest)
{
    do_something();
    CHECK(protected_field == true);
}

Nevertheless, I think this is not very clean, because problems relating inheritance could arise in some configurations and, anyway, just protected members can be accessed and tested.

I tried to declare test classes as friends, but as these are created in some special way by Uni开发者_如何学GotTest++, I haven't managed to do it yet.

Does anyone have any idea of how to make test classes friends of the the classes under test?

Is there another way of approaching this problem in an easier or different way?

Thank you all in advance.


There's one really ugly but surprisingly useful hack that I commonly use for unit testing:

#define private public
#define protected public

#include "class_to_be_tested.h"

// and here, all class's methods and fields are public :P

DON'T use it for anything else than unit testing!

Also, this method has some limitations -- firstly, not everything private is prefixed with private. Secondly, one popular compiler mangles the access specifier into the linker symbol.

Another, also not so nice method is via casting. You create a structure that has the same fields, but all public, and cast it over the pointer to your private structure. This has the downside however, that the classes need to match exactly:

class my_class
{
private:
   char name[40];
   char grade;
   int age;
public:
   //
}

struct my_class_hack
{
public:
   char name[40];
   char grade;
   int age;

}

struct hack_it* my_class_hacked = (my_class_hack*)ptr;

... you can get nasty surprises however if the compiler plays around with your code, so never use this for production code.


Unit testing is all about testing your objects through their public interface. The fact that it might be hard is why writing testable code is sometimes referred to as art. Not everyone can write testable code right away, that's why people invented XP approach of writing tests first. Sounds unrealistic, works in reality.

However, if you absolutely need to test private functions, here is a list of methods I would consider in order of my own preference:

  1. Private member variables are to be accessed via public setters and getters.

  2. I would recommend making you private member function a non-static non-member function in a namespace that can be called e.g. details or internal. Don't declare it in the header file, just define it in the same file where your class functions are defined. Add its declaration in a myClass_internal.h header file in the unit test project and test it. Difficulties involved depend largely on the complexity of your architecture.

  3. Make your test class inherit from your testable class. This doesn't involve changing your code much, but might require use of multiple inheritance, which in some places is even banned.

  4. Make your test a friend of your testable class. Difficulty depends on the test framework you are using. Say, with gtest that I use, it's pretty hard :)

  5. A hack with redefining public and private should be your absolutely last resort if everything else fails. Although I would rather think of changing the design to a more testable one instead.


This was the subject of hot debate a few years ago, but the generally accepted result was that you should only test the externally-visible behaviour of your class, and so access to its internal data and behaviour is not required.

While this may not initially sound helpful, you can extract the private parts of your class that you want to test into new classes whose external behaviour is the behaviour you want to test. You can then test these classes in the normal way, and you will improve your overall design.


I would also go for th #define Hack,

but also put a #define class struct to get implicit private class data public too.

I must disagree with Dmitry:

1.) this would add interfaces to my production code just for testing and would violate my encapsulation. I do not want clients to have access to my private data

2.) again as seen in 1.) -> good idea, if those interfaces are really only exposed for testing

3.) only works if the access is protected, which somehow also compromisses encapsulation

4.) also means modification of my production code just for testing and even creates a coupling between production code TO my testing code!!!

5.) from your point of view it is right, I rather have ugly testing code than ugly production code :)


While I agree with everyone saying "don't do that," sometimes you are working in a large project where you don't have the freedom to make all the changes to the class under test that you would like. For those situations, I would prefer a friend declaration to public/private redefinition hackery.

I figured out how to do it for UnitTest++ Here's an example for a "Deck" class with a "dealInternal" protected/private method that you would like to use from a "Internals" test.

    //------------- Deck.h -------------
    namespace SuiteDeck { class TestInternals; }

    class Deck {
        // etc...
        private:
        friend class SuiteDeck::TestInternals;
        bool dealInternal();
    };

    //------------ TestDeck.cpp ----------
    #include "UnitTest++.h"
    #include "Deck.h"

    SUITE(Deck) {
        TEST(Internals) {
            Deck d;
            CHECK(d.dealInternal() == true); // or whatever
        }
    }


One's better off avoiding testing private things. Why do want to test a private_field ? What gets wrongs when the private_field is set to an invalid value ? Is it possible to test for this wrong behavior instead of asserting on the wrong value ?

Other options include

  • play with the preprocessor to make it public when the code is compiled for unit testing

  • extract the private field and the related logic into a new class where it will be public and make the ClassUnderTest relying on this new class.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜