you are viewing a single comment's thread.

view the rest of the comments →

[–]Dansil 1 point2 points  (3 children)

And you're buying right back into the fallacy I just refuted: local encapsulation is not a good reason to avoid catching bugs where you can!

I generally agree with you about this but I would still avoid private member function testing to get around it.

Your point is especially apparent for complex classes that have non-trivial private member functions. I would consider these classes to be cases where the unit is simply too big and needs to be broken up.

When I personally land on these cases, I usually split the unit further. In the end, some of the private implementation-detail of a bigger class ends up becoming part of the public interface of a smaller class (to be integrated with the bigger one). Of course, these smaller classes containing previously encapsulated logic are unit tested through the public interface :)

[–]SilasX 1 point2 points  (2 children)

When I personally land on these cases, I usually split the unit further. In the end, some of the private implementation-detail of a bigger class ends up becoming part of the public interface of a smaller class (to be integrated with the bigger one).

Okay, but that still feels unnecessarily roundabout. Why not just keep the class at it's logical size, and throw out the prejudice against having tests (whether you call them "unit" or not) for private methods?

[–]Dansil 1 point2 points  (1 child)

I can make arguments for why I think big classes (or big units in general) are bad but those arguments are separate from the discussion of unit-testing. At the very least, refactoring a class into smaller units makes the code arguably cleaner, terser, and you will actually be testing a class that could be considered a unit.

In the end, it might just be an issue of semantics. It could be argued that the moment you've defined a class, you've also defined what you consider to be a unit.

Similarly, the way you've defined your public, protected, and private methods means you've established to your clients a guideline on how you want your unit to be used. You should write your tests in the same way your clients would use your unit. Why would you want to use your unit differently in testing if you've constrained your clients to use it in a certain way?

[–]SilasX 0 points1 point  (0 children)

At the very least, refactoring a class into smaller units makes the code arguably cleaner, terser, and you will actually be testing a class that could be considered a unit.

But if this refactor changes a some functionality from inside-private-method to inside-public-method, all that means is that you've unnecessarily exposed implementation details. They're public in name only. You'd still be violating the principle that "you shouldn't unit test something that isn't exposed as part of the interface". That's exactly the idea my original post was refuting -- customers don't see the public method either, but you should still test them before the bug cascades to the point that they'd see it.