Questioning "testable design"

After a discussion about PowerMock with @olabini on Twitter I felt I had to write a post on testability.

The truth “Autonomous, re-runnable, code-based tests are objectivity good” has created a perceived truth, namely “Testable design is good design“. This assumption is incorrect.

The phrase “testable design” is dependent of two things; the design of the code under test AND the tools used for testing the code. This is a problem when the major tools today in the Java world tells you to not test private methods, final classes
and so on.

Yes, there is a big overlap between testable design and good design, but should the test tools you use govern your design? Conscious and good design choices should govern the structure of your code, and testability should come with that.

PowerMock changes the phrase “Testable design is always good” to what it should be, and that is “Good design is always testable”.

And when it comes to the hurt of legacy code, would you rather re-factor the code in order to write tests, or write tests to be able to re-factor the code safely?

This Post Has 8 Comments

  1. Ulrik Sandberg

    You state: “‘Testable design is good design’. This derivative is faulty.”

    I’d like to point out that we’re talking different levels of awareness here:

    Level one: you have a ball of mud and you’d do anything to get away from it.
    Level two: you have a not-so-bad design and you start questioning why you have to change visibility of methods just to make them testable.

    I used to find the arguments of the level two people a little tiresome. I mean, we’re talking pretty small sacrifices to make for reaching testability; what must be seen as Nirvana when you’re down at level one. In order to reach a testable design, you’re pushed in the direction of loose coupling and high cohesion. Dependency injection, for example, makes wonders when it comes to testability. To complain about a few extra interfaces then seemed a little petty to me. “You’re missing the point”, I used to think.

    I was not a big fan of tools like PowerMock either; tools that basically cut through the seemingly insurmountable obstacles of “final”, “private”, and “static”, giving access to anything anywhere. “Wreckless youngsters”, I used to think. “They don’t know what they have started. Soon everyone will make everything ‘private static final'”. Oh, how I hated those keywords. I wanted to make them deprecated, paving the way for beautiful, testable code. I still do, actually, but I don’t talk about it in public.

    Anyway, I have changed my mind. PowerMock is the coolest thing since I don’t know what. If you want to mock a static, just do it. And a final. And a private. And a constructor. Of course, this is to be able to test code that is ugly. Just as Mattias says: “write tests to be able to re-factor the code safely”. That’s exactly the point. And I’m finally getting it.

  2. Mattias Ask

    Thanks for your comment, Ulrik!

    I totally agree. There are different levels of awareness.

    The point I hope I’m getting through is that I think the most important thing is tested code, a.k.a. working code. If you have nice and tested code, but e.g. use “protected” rather then “private” more then you’d like, you don’t have much of a problem. But still, with tools like PowerMock, we can easily correct these beauty flaws.

    If you on the other hand have an untested “ball of mud” which you want to test, you get the bonus of great improvements in the design if you use the major test-tools like EasyMock. This will come from you having to submit yourself to their restraints. But in order to get to that safe feeling of tested code, you have to jump off a cliff, and really truly believe that you wont break the thing, when you refactor it for testability.

    If you test your ball of mud with a tool like PowerMock, you can test before you refactor, and then safely re-design to perfection :)

  3. Fredrik Olsson

    I think that PowerMock is the second coming. Adjusting the design decisions based on what is testable can only result in good design, but keep the goal of perfect design out of reach.

    In my experience testable design, is almost always over designed, and therefor hard to maintain without tests. The solution sort of creates the problem.

    I see PowerMock as the better solution, that leads to less problems and more cleanly designed code.

  4. Andrew Clegg

    “This is a problem when the major tools today in the Java world tells you to not test private methods, final classes and so on.”

    Who tells you not to test final classes? Sure, some tools make it hard to mock out final classes, in order to test *other* classes that depend on them, but that’s a different issue.

  5. Mattias Ask

    True, Andrew. It’s of course the classes using final classes that are hard to test. My mistake.

  6. Giorgio Sironi

    Imho you’re leaving out the other side of the coin :)
    When it comes to testing private methods, we should not do it as they are not part of a contract. We are testing the interface of our class and other ‘units’ of the application works against this interface, even if this interface is implicit, when there is only a concrete class. A private method is internal and it’s an implementation detail.
    What java gurus, etc. say is to factor out the private method in an other class that is composed by the first one; for example a Repository can use a QueryFactory instead of a private _createQuery() method. Then you can test the public method on QueryFactory but leave the instance in Repository private to preserve encapsulation.

  7. Mattias Ask

    Hi Giorgio! I agree. If done right, private methods are most often parts of the unit under test and should be pretty uninteresting to test by them self. My point here is that if you get, have or even want to write code that has private methods that are interesting to test separately, why shouldn’t you be able to test them separately?

    With PowerMock you can basically test any part of your code separately, and mock whatever parts you feel relevant to mock. This enables you to verify that your code works, regardless of architectural choices made. Personally, I think it is “Working code over correct architecture”, if you excuse the play on the agile manifesto :) But, of course, I also need to add a version of the last sentence of the same document: “That is, while there is huge value in the item on
    the right, I value the item on the left more.”.

  8. Giorgio Sironi

    For the practice of factoring out, I’ve just written an article on that:
    that pretty much says my opinion is the opposite of yours :)
    What I think is:
    – they are interesting to test, so
    – you write tests that explains the behavior of the methods
    – a test defines a contract for the code exercised
    – so these methods should be public, because a developer that is refactoring does not touch public methods, but can delete private ones
    – and so I put them in another class to preserve encapsulation (private instance in the main class).

Leave a Reply