Testing private methods? t'aint nothin

Wednesday, January 16, 2008

I decided to make a case study out of the development for Issue 48 i.e. making private methods testable. I took screenshots at every step of the way and plan to document it all. I think it'll provide insights into the tiny little iterations and sometimes inconveniences one encounters when unit testing; it'll also show how to easily overcome them. Just as importantly, it should demonstrate the tremendous benefits of unit testing. I find that what I like about mxunit is that for the most part it doesn't make it too tough to see the information I need to see when I'm developing. I like cfdump. I like seeing the data I'm dealing with (does the string have periods or back slashes? what keys are in the getMetadata() struct for this here function, anyway?) But more on that later. Oh, and how to test private methods, i.e. private functions, i.e. <cffunction .... access="private"> (or access="package")? That's pretty easy. Well, now it's easy, anyway.


seancorfield said...

Why not simply create a mock that extends the component under test (since "private" in ColdFusion is really protected - and can be called by extended classes).

Then your mock can contain wrapper / setup methods and can call any private methods in its base class.

Marc Esher said...

Well...there was always that, too. But in the end, I'm sticking with this answer: this was more fun.

Bad form, I know.

My other answer is that for me, as the only person in the department who even writes tests, whose bosses would rather he not even "waste" time on that stuff, this way is just easier. it's easier to remember, it's easier to snippetize, and it's easier for other folk to understand when they do look at my tests (though that doesn't happen).

I guess I'm lazy.

seancorfield said...

I wasn't criticizing. Yours is an interesting approach (although you didn't show what makePublic() does). I was just wondering why you didn't take the approach that is usually recommended for testing private methods.

My only concern about your method is that you are probably modifying the object under test in order to call its private method? That would sort of invalidate the test (because you're not testing the actual class - which is not a concern with the extension-and-call-super approach).

seancorfield said...

OK, I went and looked at the code and, yes, you are modifying the object under test (and your example in the article looks wrong - shouldn't it be calling myObj._somePrivate() instead of just _somePrivate() which would be a method on the test case?).

Your makePublic() code is much more complicated than just extending the object under test and it is invasive - and it isn't thread safe.

BTW, in your MXUnit documentation, you have "Refactor the component" when in fact it's writing the first code. Refactoring is when you change existing code that already works to produce the same testable result in a better way.

Marc Esher said...

Jeeeesh: one thread safety bug and 2 documentation errors; on a Sunday; in someone else's code.

You should be a consultant or something. ;-)

Thanks, Sean, for improving our project.

seancorfield said...

We aim to please :)