testdriven.com Wrangling quality out of chaos

Posts Tagged ‘Junit’

Taming Legacy Grails Code with Test Generation

04.14.2013 · Posted in Articles, Automatic Testing, Selenium

In his seminal book, Working Effectively with Legacy Code, Michael Feathers defines “legacy code” as code without tests. Unfortunately this is exactly what my team wound up creating towards the end of our Groovy/Grails project. We were hoping that our Selenium tests would cover both the JavaScript in the browser and the Groovy code in the controllers. Unfortunately, due to several issues which are outside the scope of this article, we could not get a robust set of tests that ran fast enough so we decided that the pragmatic thing to do was to abandon the Selenium tests — the project has a rather large QA component so the risk to business was well mitigated. We soon realized that the untested code in the controllers was giving us problems with typos not being found for many days because Groovy 1.8 is a dynamic language.

To quickly rectify the situation we decided to implement a record/playback strategy. In most situations I would be against using record/playback automation tools, by the beautiful thing about software development is that its so contextual and I think this was the right move for the moment.

We wrote a small code generator that produced simple Selenium tests using the HtmlUnitDriver. The generator was triggered by a call in a ‘MyFilters.groovy’ file when the application was tested manually. For every controller/action combination, the generator intercepted the params map and generated the test with the values in the map. The initial assertions were simple — they just checked to see that nothing obviously bad had happened — such as 404 or 500 errors. It took about 1.5 hours to write the generator and then we stepped through the application manually and generated many dozens of tests. Because there was no Ajax involved the tests were 100% reliable and ran in about 90 seconds.

This simple approach allowed us to be sure that when we do refactor our code, we will catch the basic mistakes that a compiler would catch for us. We got an additional bonus when we caught a bug in our sample data that violated a Hibernate constraint.

In our situation, writing a simple record/playback tool was the right move. It took less that a day to implement and it already paid for itself many times over.