Sunday, January 6, 2013

Patterns of Testable Software

Patterns of Testable SoftwareMy love for test driven development started a few years ago, when I first had a taste of it while working on a product in a startup company. I started out using TypeMock, a really wonderful framework that allows you to isolate the code you want to test from its external dependencies, without having to change the way your code is designed. Within a few months, my team and I completed our work, met our deadline, and we were confident in the product, because we had tests to prove that it works.

Writing Unit Tests is Easy! Good Tests… Less so

Writing unit tests is easy. All you have to do is choose a single use-case of a method that you’re going to test, set up its inputs, and measure the output against some expected result. If it matches, then the test passed. If not, it fails. Rinse and repeat.

Our problems started after that. With the next version, we had to modify our code. No problem, we thought. Our code has unit tests. We can refactor without fear, because our tests will tell us if we’re breaking anything. Except it didn’t. Because of the way our software was written, and because of the way we mocked our dependencies, our tests were tied in to the implementation of the code, rather than the end results. This meant that our tests were brittle, and fragile, because the tests broke whenever we changed our internal implementation. Our tests were starting to “cry wolf”. We abandoned them quickly.

As it turns out, it is not enough “just” to write tests. You actually have to write the production code in a way that is easily testable. Your code has to be written in such a way that you can verify the outcome of a method without depending on internal implementation details. As time passed, I became more and more proficient at doing this, while becoming increasingly frustrated at the difficulties that beginners have. I see many good programmers giving up early, because the tests fail them, because it is difficult to get existing (legacy) code under a good test harness, and because they keep hitting a wall with the question of “how do I test this?”.

Patterns of Testable Software

I have recently begun trying to codify recurring patterns of software that is easily testable: Patterns that developers should strive to conform to, or refactor their code to. Patterns that help developers test the state of a module after running it, as well as to test the behavior of the module when running. Patterns that test the outcome without depending on implementation details.

On Thursday, January 24th, 2013, I am going to present some of these patterns for the first time, at the Toronto ALM User Group. At the time of this writing, there are still some open spots. If you’re in the neighborhood, and are interested in Test Driven Development or writing unit tests in general, I think that you’ll find the material quite rewarding. You may register for free at http://www.meetup.com/Toronto-ALM-User-Group/events/97454932/

I hope to see you there and if I do, I hope you’ll enjoy the session.

Assaf

P.S. Oh, and happy new year!