This coming spring we will host a course with Robert C Martin on advanced TDD. I would really appreciate the input from my experienced TDD readers on what they consider to be the largest obstacles when it comes to TDD. This is your chance to shape the event so that it is customized to meet your needs.
A few months ago we hosted a very popular course with Michael Feathers. He talked about refactoring legacy systems and of course, unit tests which are an essential part of that. But the crowd cried out for more.
I have been practicing TDD for two years. I program in Java and frequently use Mockito and Wicket. The latter has support for unit testing web interfaces and it is great although it has its quirks.
But what is everyone else doing?
In my experience the GUI is the hardest part to develop using TDD, at the same time there is a lot to gain by using TDD. You really, really want automated tests instead of manually clicking through your interface.
A GUI can be built many ways and on different platforms. I mentioned web, where there are different technical issues with different frameworks. There are also Swing-based Java applications and mobile platforms.
How can you test the GUI? There are several different options. You can send events, but there are issues ensuring that the event reaches the correct control, timing issues and performance problems.
You can go slightly under the surface by programatically calling the functions that should be invoked by the events. But you may run into issues with correctness. For example, the button you try to test a click on may not be visible.
You can argue that a GUI is not considered done until a human has looked at it. Yes, but that is no excuse for not writing tests.
There are of course other complicated scenarios. Take multi-threading, how do you handle that?
Besides the technical problems, there are also social problems.
The first that springs to mind is that there is a feeling that it takes too long to write the tests. As a TDD addict, you know that this is an illusion. You reach "done" on the Scrum board faster when you write tests. The feeling stems from the fact that time feels shorter if you sit staring at the code thinking instead of expressing yourself in code. Also, if you don’t write tests, time gets split up between implementing and fixing bugs. So the latter does not included in the former, as it should. "Oh, I’m done, there are just some bugs to fix".
There is also a fear that maintaining the tests takes too long. That may be quite true. If you write code that is hard to maintain, it will apply to your test code as well. If the code you test has poorly designed interfaces that change frequently, that will adversely impact your test code AND other clients. Maintenance will always be necessary. As the requirements change, the tests need to change.
It’s important to point out that TDD is not about testing, it is about specification. That is why some people prefer to say BDD instead. It is a common misunderstanding that TDD means testing. That manifests itself in comments like "even though you wrote unit tests, there are bugs".
Real testing is a different animal altogether which can make use of the same tools.
It gets fuzzy. When should you stop and say that there are enough unit tests to specify the behaviour of the unit and when do you do real testing with bounds checking etc? And does it matter when?
Another social problem: How do approach co-workers who refuse to write unit tests?
The problem is not just that they are slower and missing their own potential. The larger problem is that they are not writing specification.
We are agile now, so we don’t write requirements in Word documents that are printed and read and transformed into test documents and design documents that are printed and reviewed and changed and printed again when they are finally approved for use in coding which uncovers contradictions, fuzziness and other problems which render the design document obsolete and now the requirements are also obsolete so the requirements document changes and gets printed …
We talk directly to the product owner. We have little notes that are topics for discussion. We jot down a few remarks on the notes. Then we code and when we are done, we can throw the notes away.
So where is the specification? Anyone who has tried to make changes to a legacy system knows that there is none but the code. Not even when there are huge systems of documents that are supposed to describe the system.
If you don’t write documents that specify the system and you don’t write unit tests that express what the system should do, the only thing left is the system itself and that is not enough. The system mixes the purpose with the solution on every line of code. And you are in legacy land from day 1.
But now I’d like to hear from you! Comment here or mail me (per.lundholm at crisp.se). What have I missed? What do you think should go into an advanced class on TDD?