Wednesday, July 18, 2012

Test Driven Development - Recording I

Sometime back, I was working on the development of a service (as part of my work). It was actually a rewrite involving conversion of a legacy EJB based service into simple POJO based service exposed to the external world through Spring remoting. As I had been practicing TDD (and leaning towards behavior driven tests) for sometime, I decided to use the same technique for this work as well. I decided it would be good to record some of my thoughts or opinions about what I was doing and that is why this write up. Though the rewrite use case is the not the typical use case for TDD (which is developing on green field), where it is considered to come out in all its glory, I still felt there are some good points which came out this exercise. Here are a few of my observations of doing TDD with behavior based testing:
  • Let us take a scenario where the Object under test is interacting with third party code. When we do behavior based testing in this scenario, we need to get to know more details of the implementation of the third party code. I did not like it much and started feeling the behavior based testing is making me do this thing, which felt wrong. But later on, I realized that behavior based testing is actually bringing out the fact that the third party code is actually not designed properly and hence the reason for my strife. So this gives me a chance to fix that piece of code. Now, this is nice if I have control on the 3rd party source code. If I have no control on the 3rd party source code then I probably have to move away from behavior based testing to avoid brittle tests.
  • In the pursuit of truly isolating the method under test, I try to mock out all other significant method calls whether external calls or internal methods calls (thanks to mockito's spy). In order to do that I have to increase the visibility of these methods from private to default (package level). I actually don't like doing this. The only saving grace is that the visibility is increased to package level only which still means that it is only visible within its part/sub system of the application.
  • As I write these behavior based tests, I find them very very close to the implementation. So I know that if I have to change the implementation I have to change the tests as well. I am not sure whether this is a completely bad thing. Giving that test is supposed to drive the development, this might be something which is expected (want to think more about this).
  • I realized that as I keep developing through TDD and behavior based tests, I tend to make methods much more granular and cohesive. The methods tend to be small and focused on a single task. This made it easy to test them by mocking other things out. This is a very pleasant outcome of TDD for me.
  • One thing I observed during the process of development is that it is important to have a good set of integration tests. This allows me to catch wrong assumptions I have made during writing of unit tests. Unit tests because of their nature are very focused and hence suffer from shortsightedness. Integration tests help me to overcome this problem.
  • When I am trying new stuff during implementation (say a new technique of persistence etc.) I find it worthwhile to write a integration test immediately after writing a unit test (and the implementation as they go together). This allows me to check out whether the technique is working fine. This idea is just taking the concept of iterative development to a micro level.
As I continue with development, I feel the need to go back and read some of the state vs behavior driven tests related articles. The starting point probably can be 'Mocks Aren't Stubs' article be Martin Fowler. But this time I have decided to read more of them (or may be a book) to get a better idea. Some day I will share what I learn from that.