3

if I have a class with a helper (private member) class within it, like this

    class Obj;
    class Helper {
        friend class Obj;
        private:
        int m_count;
        Helper(){ m_count = 0;};  // Note this is a private constructor
        void incrementCount(){
            ++m_count;
        };
    };
    class Obj {
        Helper *m_pHelper;
        // note that this is a private getter
        int getHelperCount() { return m_pHelper->m_count; };

        // the public API starts here
        public:
        Obj() { m_pHelper = new Helper(); };
        void incrementCount(){ m_pHelper->incrementCount(); };
    };

So how may I TDD such a system?

    auto obj = new Obj();
    obj->incrementCount();
    // what to assert???

That is my question and the following is just some background.

Response to some answers and comments.

If noone outside the class should be interested, then your tests should not be interested either. – Arne Mertz

If nobody is interested in the value outside the class, why are you – utnapistim

Even if no one outside needs the value, I may still want to know that if it's set correctly, as it is used by other self contained internal method of the class that use that value. Maybe the value is the speed where the controller will use it to update the model. Or maybe it's the position where the view will use it to draw something on the screen. And in fact all other components of Obj would be able to access that variable. It may be a bad design issue, and in this case I would like to know what better alternatives I can have. The design is listed in the background section at the bottom of this post.

define private public - Marson Mao

Love this ingenious abuse of keywords haha. But may not be concluded as the best solution just yet.

You need to "expose" the friendship relation in the header of your class. Thus you have to acknowledge there the existence of a class used to test yours. If you use the pImpl idiom, you could make the members of the pImpl itself all public, the pImpl itself private and give your unit tests access to the pImpl - CashCow

Does this mean that I should friend the test in my original class? Or add extra "test" methods to it? I just started TDD very recently. Is it common (or better is it good) to intrude the original class with test class dependency? I don't think I have the appropriate knowledge to judge. Any advice on this?

Miscellaneous: AFAIK TDD is not just writing test, but instead a development process. I have read that I should only write tests to the public interface. But the problem is, like the situation in question, most of the codes etc are contained within private class. How may I use TDD to create these codes?

Background

FYI if you would like to know why I am making a private class: I am developing a game from cocos2dx. The game engine adopts a Node tree structure for the updates, rendering etc and every game object would inherit from a Node class provided in the engine. Now I want to implement the MVC pattern on a game object. So for each object I basically created a Object class with 3 helper classes corresponding to each of the MVC components named ObjectModel, ObjectView, ObjectController. Theoretically no one should access the MVC classes directly and would only be accessed somehow through the Object class so I make the 3 of them private. The reason of making the MVC components explicitly as classes is because the View and Controller are updating at different rates (more specifically the Controller performs frame dependent updates, while the View do a simple interpolation based on the model data). The Model class is created purely for religious reasons lol.

Thanks in advance.

Community
  • 1
  • 1
hailstone
  • 113
  • 1
  • 5
  • 3
    Test the public interface. – duffymo Aug 13 '14 at 09:36
  • When you create an `Obj` instance, the `Helper` instance should have its counter set to zero, you can test that. Then increment, and check that the result is one. And since the "increment counter" and "get counter" is the only public functions, that's all you can test. – Some programmer dude Aug 13 '14 at 09:39
  • The problem is I don't even have a getter in the public interface. So how can my test check that the value is 0 or 1? And the getter is intentionally made private as no one should be interested in the value outside the class. – hailstone Aug 13 '14 at 09:42
  • If noone outside the class should be interested, then your tests should not be interested either, because then it simply does not matter wether that value is 0 or 1 or 54 as long as the class behaves correctly. If your class needs that value for some publicly available function, test that function. If your class does not need that value for any function in the public interface, then throw the value away alltogehter, becasue then it has no use at all. If what you want to test is some more general algorithm your class relies on, then put it in its own class and unit-test it separately. – Arne Mertz Aug 13 '14 at 12:07

5 Answers5

4

How to test friend functions of private class?

Thou shalt not!

A class (or module or library or whatever) exposes a public interface for a reason. You have the public interface (which is geared for client use, so it has invariants, preconditions, postconditions, side-effects, whatever - which can and should be tested) and implementation details, that allow you to implement the public interface, easier.

The point of having a private implementation, is that you are allowed to change it as you please, without affecting other code (without affecting even tests). All tests should pass after you change your private implementation, and client (and test) code should (by design) not care at all that you changed the private implementation.

So how may I TDD such a system?

TDD your public interface only. Testing implementation details means you end up coding to an implementation, instead of an interface.

Regarding your comment:

The problem is I don't even have a getter in the public interface. So how can my test check that the value is 0 or 1? And the getter is intentionally made private as no one should be interested in the value outside the class

If nobody is interested in the value outside the class, why are you (i.e. why would you wish to test for it?)

utnapistim
  • 26,809
  • 3
  • 46
  • 82
  • Not sure if it's right, but in my case, I want to test those value to make sure everything goes well. I can make a test and run it every time when I modify my class (no matter public or private). If the test passed, then I know I didnt break anything up. For example I made a `std::map`-like class, `MyMap`; I made a unit-test for it, designed some procedure like many `insert` then `erase`, then test all inner values of `MyMap` object to make sure the implement is correct. Next time I change my private implementation of `MyMap`, then I run the test again to check if the result is still correct. – Marson Mao Aug 13 '14 at 10:50
  • If you want to test the effects of a private function, figure out how it affects the output or side effects of your public functions, and write tests for those. These tests will be more difficult to write, but they will end up being corner cases for your public API. These tests will be _invariant of your implementation details_ (as they should be) and written for your corner cases (this is an ideal scenario). – utnapistim Aug 13 '14 at 12:26
1

I have encounter such problem when I was writing unit test as well.

After some searching I decided the most effective way is to add this in your Test.cpp:

#define private public

NOTE: add this before your desired include file, maybe your Obj.h, for example.

I think this method looks crazy but it's actually reasonable, because this #define only affect your test file, so all other people using your Obj.h is totally fine.

Some reference:

Unit testing of private methods

Community
  • 1
  • 1
Marson Mao
  • 2,935
  • 6
  • 30
  • 45
1

I vote, as @Marson Mao says, for #define private public.

If you want to control what to make private or public a bit more, you can do this in yourtests.cpp

#define private public
#include "IWantAccessViolationForThis.h"
#undef private
#include "NormalFile.h"

This way you can have a bit more control and try to do this trick in as few places as possible.

Another nice property of this approach is that it is non-intrusive, meaning that you don't need to clutter your real implementation and header files with #ifdefs for testing and not testing modes.

Germán Diago
  • 7,473
  • 1
  • 36
  • 59
  • 1
    +1 for undef private and non-intrusive; I think non-intrusive is the best part of `#define private public`. – Marson Mao Aug 13 '14 at 10:52
1

The #define private public trick can have side effects with the way some compiler are mangling function symbols (Visual c++ compiler is including access specifier in its name mangling)

You can also change visibility with the using statement :

struct ObjTest : public Obj
{
   using Obj::incrementCount;
}

But like other people said, try to not test private stuff if possible.

  • NB: Another side effect of the #define private public would be the attribute order rearrangement depending of the access specifiers on some compilers. –  Aug 13 '14 at 12:00
0

Your friend has full access to the class that it is a friend of. This might be done for many reasons and one of those could well be for unit-testing purpose, i.e. you want to be able to write a unit test that can call private members of the class and check the internal variables show what you would expect them to show, but you do not want that to be part of the public API.

You need to "expose" the friendship relation in the header of your class. Thus you have to acknowledge there the existence of a class used to test yours. No worries, you develop in the real world and classes are tested.

In order to write a unit test you will want to implement that class to provide protected member functions (probably static ones) that call all the relevant private functions or get the private members, and then you write classes that derive from yours. Note that those will not have direct access as friendship is not inherited, thus the static protected members.

If you use the pImpl idiom, you could make the members of the pImpl itself all public, the pImpl itself private and give your unit tests access to the pImpl (through the same model as above). This is now simpler as you only need to create one method for your "tester".

With regards to data members of a class, in recent years I have been known to put all these into a struct, i.e. have them all public, and then for the class to have a private instance of that struct. It can be easier for handling this kind of thing, and also serialisation / factories to your class, where they can create the struct which is all public, then construct your class from it.

CashCow
  • 30,981
  • 5
  • 61
  • 92