Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing c++. How to test private members?

I would like to make unit tests for my C++ application.

What is the correct form to test private members of a class? Make a friend class which will test the private members, use a derived class, or some other trick?

Which technique does the testing APIs use?

like image 964
Daniel Saad Avatar asked Jan 06 '13 20:01

Daniel Saad


People also ask

Can we test private methods in unit testing?

Unit Tests Should Only Test Public Methods The short answer is that you shouldn't test private methods directly, but only their effects on the public methods that call them. Unit tests are clients of the object under test, much like the other classes in the code that are dependent on the object.

Is there any direct way to test private method?

To test private methods, you just need to test the public methods that call them. Call your public method and make assertions about the result or the state of the object. If the tests pass, you know your private methods are working correctly.

How do I unit test private methods in Xunit?

A quick solution is to make private members that you want to test internal . You can then add an InternalsVisibleTo attribute to your main library's AssemblyInfo. cs. This will allow your test library (and no other library, without reflection) access to the internal methods/classes in your main library.


2 Answers

Typically, one only tests the public interface as discussed in the question's comments.

There are times however when it is helpful to test private or protected methods. For example, the implementation may have some non-trivial complexities that are hidden from users and that can be tested more precisely with access to non-public members. Often it's better to figure out a way to remove that complexity or figure out how to expose the relevant portions publicly, but not always.

One way to allow unit tests access to non-public members is via the friend construct.

like image 85
Mr Fooz Avatar answered Sep 24 '22 02:09

Mr Fooz


Answering this question touches many other topics. Beside any religiosity in CleanCode, TDD and others:

There are several ways to access private members. In any case you have to overrule the tested code! This is possible on both levels of parsing C++ (preprocessor and language itself):

Define all to public

By using the preprocessor you are able to break encapsulation.

#define private public #define protected public #define class struct 

The disadvantage is, that the class of the delivered code is not the same as in the test! The C++ Standard in chapter 9.2.13 says:

The order of allocation of non-static data members with different access control is unspecified.

This means, that the compiler has the right to reorder the member variables and virtual functions for the test. You may struggle, that this won't harm your classes if no buffer overflow happens, but it means, that you won't test the same code as you deliver. It means, that if you access members of an object, that was initialized by code, compiled with private not defined to public, the offset of your member may differ!

Friends

This method needs to change the tested class for befriending it with the test class or the test function. Some testing frameworks like gtest (FRIEND_TEST(..);) have special functionality to support this way of accessing private things.

class X { private:     friend class Test_X; }; 

It opens the class only for the test and does not open up the world, but you have to modify the code that gets delivered. In my opinion this is a bad thing, because a test should never change the tested code. As a further disadvantage it gives other classes of the delivered code the possibility to intrude your class by naming themselves like a test class (this would also harm the ODR rule of the C++ Standard).

Declaring the private things protected and derive from the class for tests

Not a very elegant way, very intrusive, but works also:

class X { protected:     int myPrivate; };  class Test_X: public X {     // Now you can access the myPrivate member. }; 

Any other way with macros

Works, but has the same disadvantages on standard conformity like the first way. e.g.:

class X { #ifndef UNITTEST private: #endif }; 

I think that the last both ways are no alternatives to the first two ways, because they have no advantages over the first ones, but are more intrusive on the tested code. The first way is very risky, so you may use the befriending approach.


Some words on the never-test-private-things-discussion. One of the upsides of unit testing at all is, that you will reach very early the point, where you have to improve the design of your code. This is also sometimes one of the downsides of unit testing. It makes object orientation sometimes more complicated, than it has to be. Especially if you follow the rule to design classes in the same way the real world objects are.

Then you have to change the code sometimes into something ugly, because the unit testing approach forces you to do so. Working on complex frameworks, that are used to control physical processes, is one example. There you want to map the code on the physical process, because often parts of the process are already very complex. The dependency list on that processes gets sometimes very long. This is one possible moment, where testing private members is getting nice. You have to trade-off with the advantages and disadvantages of each approach.

Classes are getting sometimes complex! Then you have to decide to split them or to take them as they are. Sometimes the second decision makes more sense. In the end it is always a question of which goals you want to achieve (e.g. perfect design, quick incorporation times, low development costs...).


My Opinion

My decision process for accessing private members looks like this:

  1. Do you need to test private members themselves? (Often this reduces the total number of tests needed)
  2. If yes, do you see any design advantage to refactor the class?
  3. If no, befriend the test in your class (use this because of the missing alternatives).

I don't like the befriending approach, because it changes the tested code, but the risk to test something, that may not be the same as delivered (as possible with the first approach), will not justify the cleaner code.

BTW: Testing only the public interface is also a fluent matter, because in my experience it changes as often as the private implementation does. So you have no advantage to reduce the test on public members.

like image 27
Stefan Weiser Avatar answered Sep 24 '22 02:09

Stefan Weiser