views:

265

answers:

5
+4  Q: 

testing classes

I put together a class yesterday to do some useful task. I started alpha testing, and at some point realized I was adding alpha test related methods to the class itself. It hit me that they don't belong there. After a bit of head scratching I derived a test class from the base class that has access to the protected members as well. I put all of the testing related methods, and set up and tear down in the test class, and left the base class lean and mean as the old saying goes.

After browsing around here awhile I found one comment that suggested using this sort of technique by making the testing class a friend of the real class.

In retrospect both of those techniques should have been obvious to me.

What I am looking for, are techniques for specifically alpha testing/unit testing classes, without adding to the weight of the class being tested.

What techniques have you personally used, and recommend?

+9  A: 

One of the goals of unit testing is to verify the interface to your classes. This means that, generally speaking, you shouldn't be testing the dirty innards of your class. The unit test is supposed to interact with the public inputs and outputs of your class, and verify that the behaviour is as expected. You are thus able to change the internal implementation of your class without affecting all of the other objects that depend on it. Obviously, I don't know the details in your situation but I would say that, as a general rule, if your unit test is trying to figure out the private details of the class, you are doing something wrong.

edit: See also: This SO question. Notice that it can be done (top answer), but also notice that the second-place answer (by a short margin) says more or less the same thing as I mention above.

e.James
But at the same time, sometimes you want to examine the internal state of the object. Or unit-test a private method to ensure that it works properly "as a unit" - without the "system test" of the public methods that call the private method.
Jeff B
Yep. I see your point. Unit testing is being used with a wrong definition.
EvilTeach
@Jeff B: Absolutely. I have been in that situation many times, however it has always been because I was doing something wrong. Whenever a class has such complicated innards that I find myself wanting to test them, it means that I need to refactor that class into more practical parts!
e.James
When you want to test private stuff, consider extracting it to a dedicated class where it will be public so that you can test it in isolation. Instantiate this new class so that it is private to your initial class.
philippe
Ya. I didn't find the other SO question when I looked.Thanks eJames.
EvilTeach
@eJames: Yes, but often times those more practical parts are still private/internal to the library and not to be exposed to the consumer of the primary interface. It gets tricky to test the library-internal objects when the test code is in a separate library.
Jeff B
@EvilTeach: No worries. This question is slightly different anyway, and this stuff bears repeating
e.James
@Jeff B: Fair enough. No rule is absolute :) I like philippe's suggestion in that case.
e.James
A: 

Those are good. I have usually also wanted the test class to not only be spearate from the original, but also in a complete different DLL/EXE, as well as testing the "real" compiled class from the "real" DLL/EXE into which it was compiled.

The one additional technique I've found is to re-define the class within the testing tool. Copy the class definition exactly, but make everything public. This allows the test tool to have 'white-box' access to the class, but the actual implementation is still from the real class code.

i.e.

class myClass
{
private:
    int foo;
public:
    myClass() { foo = 0; }
}

and then:

class test_myClass
{
public:
    int foo;
public:
    test_myClass();
};

void test()
{
    myClass *c = new myClass();
    test_myClass *t = (test_myClass*)c;
    // All methods are called on c.
    // White-box access is available through t.
};

Oh... and DevStudio 2008 now has some really cool unit testing capabilities, including the ability to declare a 'friend' assembly, which allows white-box access to all your internal classes in the assembly being tested.

Jeff B
You're violating the one definition rule here, among other things changing accessibility modifiers can change the layout, which would be disaster.
Ben Voigt
A: 

I have done a lot of framework building - basically calling the classes/interfaces I wanted to test. There was no additional work in the classes.

I also built classes a few times that made the public methods virtual. I derived from those and made test classes/objects. The test object methods called the parent (real class) methods and also logged all calls and results. This was more for logging than testing, but it worked as well.

The methods above I did before all the hype about unit testing and the like. (circa late 1990s)

It worked well for me then, but I have not done too much with the Junit/nunit stuff and am eager to actually give them a whirl on real projects.

sample for one method

class Thing

{...

public: virtual DoStuff(); . .. };

class ThingTest : public Thing

{

virtual DoStuff()

{

//log the call and the parameters.

// make the call to the parent

// log the return value

// return the return value

}

};

Tim
A: 

eJames is right Unit Testing needs to focus on Interface that the inputs into the Class are producing the correct Output. Any private or friend variable are part of the implementation and are not tested specifically.

If you had made an error in a private routine to the class then it would show up incorrect output.

RS Conley
+1  A: 

It sounds like you don't want Unit testing, which is correctly the verification that the interface of a class works. You shouldn't have to change your class at all in order to do unit testing. If you are looking for a way to verify the internal state of your object so that it remains consistent, you should look into Design by Contract methods, which can verify internal state from within the object.

jamuraa