Have you written unit tests only later to find they slow you down because your changes cause a lot of test breakage? You think, these tests are not living up to the promises I heard. So you toss the tests and go back to business as usual.
Hey, not so fast. Maybe its not test in general, but your tests or your code. The first project I used TDD on in 1999/2000 we ran into this problem. Some were ready to give up. But I wanted the tests to work and looked for what was wrong. In our excitement we kept copying, pasteing and tweaking the test cases. They were an ugly (in hindsite) mass of duplication. Small changes made for ripple effects through the tests. But I could see, it was our fault.
Someone on Quora asked me “How do you make unit tests less brittle”. Here is a more complete answer based on having written my own bad tests and seen many learners of TDD and unit testing go the wrong direction with their designs and tests.
Being one of the people that participated in the creation of the Agile Manifesto, I find myself very disappointed by the reaction of engineers to the question “Are you practicing Agile?” Their shoulders drop. They start to slowly shake their heads. They mumble; they grumble. They tell me agile is horrible. I ask why. Reasons I head most often are:
I saw this picture on top of an article about some new web technology. What strikes me is that most this code has to do with debugging. It looks to me the programmers maintaining this code have sprinkled debug statements through the code to see what the code is doing.
Its Friday night, do you know what your code is doing?
I spend the day updating the Fake Function Framework, Mike Long’s (@meekrosoft) creation. With my client last week, one of the engineers had some problems with Visual Studio (don’t we all) and the Fake Function Framework (a.k.a FFF). I promised to integrate the changes into the FFF. The FFF is created with a ruby script, but you don’t have to care about that unless you have functions to fake that have more than 10 parameters. But anyway, I spent the day updating and reviewing the ruby script that generates the FFF.
As programmers adopt test-driven development, they are going to prevent many defects that would have escaped to testers. Programmers that write unit tests just after programming are going to find many of the defects that would have escaped. Keep in mind that the programmer tests only check what the programmer thinks the code is supposed to do. The tests do not assure the code meets the customers’ needs. But making sure the code is doing what the programmer thinks it is supposed to do is needed for high quality systems. They work on purpose, rather than by the accident of offsetting defects.
Testers, and the whole team, are responsible for making sure the product does what they think the customer needs. These are different tests, they cover more code per test as well as checking the interactions between modules. As testers adopt automated testing, they need different skills than the manual tester that is following a script or exploring. Some adopt Acceptance Test Driven Development. For testers in this environment, the world is changing. Changing for the better with the intellectual challenges of automation, keeping the cost of retest low, and reducing the repetitive, error prone and boring manual tests. Not all manual tests go away, but we work to automate what is repetitive. In addition ATDD moves testers upstream from reacting to the code written to specifying system behavior by example.
All that said, most of the world of software development still practices Debug Later Programming and manual test, the same practices I used in my first job as a programmer. Congratulations for using 1979 programming techniques! We’ve learned a lot since then.
For some adopting TDD and ATDD is changing their world. For most it is not. There is so much legacy code out there, as well as people and organizations that do not know how or why to automate their tests, that the status quo of testing will likely have a long life.
Upper management actually asked me to share my TDD experience as well & so I just published an article internally to our Embedded Software newsletter describing how TDD helped my project. Here’s the summary from that article (I think the dates really say it all):
While in Singapore, we visited the Leonardo da Vinci exhibit at the Marina Bay ArtScience Museum. We took the guided tour with expert from Milan. We think he was a Catholic priest by the roman collar. We were both amazed at the great influence and knowledge da Vinci had in math, science, art, music, technology, weapons, architecture…
Kent Beck told me years ago, if the code does not need to work, then there is no need to test it. He continued and observed, why bother writing it if it does not need to work. Since hearing that and discovering how frequently I make coding mistakes, I want thorough tests.
Maybe you are asking yourself “I’ve got integration and system tests, why do I need unit tests?”. The answer is simple, simple math.
Here is a good question, and my reply, from a recent attendee of my Test-Driven Development for Embedded C training.
As I work more with TDD, one of the concepts I am still struggling to grasp is how to test “leaf” components that touch real hardware. For example, I am trying to write a UART driver. How do I test that using TDD? It seems like to develop/write the tests, I will need to write a fake UART driver that doesn’t touch any hardware. Let’s say I do that. Now I have a really nice TDD test suite for UART drivers. However, I still need to write a real UART driver…and I can’t even run the TDD tests I created for it on the hardware. What value am I getting from taking the TDD approach here?
One of the biggest challenges for someone experiencing TDD the first time is working in the small steps. The small steps of TDD appear to be an independent discovery of John Gall’s observation described in the Systems Bible: