If a code base is well tested and very stable, it’s pretty easy to write more tests for it. But, how do you get started writing automated tests if your legacy application has none? It’s very difficult to get started because the code wasn’t written with tests in mind. Normally, the endeavor will have you pulling your hair out. This is unfortunate because a lot of untested code desperately needs tests, yet it takes an inordinate amount of effort to write them. In this article, I’m going to tell you about a tool that you probably haven’t heard of that can help you get that legacy code base tested. It’s called Approval Tests, and here’s how it works:
Imagine you have this extremely complex machine in front of you and you don’t really know how it works. For all intents and purposes, you can think of it as a black box. You have no idea what is going on inside of it, but you see that it has a coin slot as input. You notice that every time you put 25 cents in, a rubber duck pops out of the machine. You make note of that. Then you notice that every time you put a penny in, a rubber eraser pops out. You make note of that, too. You try every permutation of input you can think of and you record the output. Now, you still have no idea how this machine works internally, but if you opened it up and tinkered with it, you can feel pretty confident that you’d notice if you broke something. All you’d need to do is try all the inputs again. If an output changes, you must have changed some functionality. For example, if you tinker with the insides and now putting 25 cents in pops out a mustache comb, you know you broke something because 25 cents used to make a rubber duck pop out. But, if each input leads to the same exact output as before, you probably didn’t break any functionality. As humans, it would be a painstaking process to try every input and record every output.
Approval Tests was created to make this task easier. You decide what inputs to pass in and you tell it what to record. From that point on, you can attempt to refactor the black box and it’ll tell you if the output changed in some way. And it comes with a bunch of tools for recording and diffing output. For example, it can check the contents of a database table, an XML file, a String, and so on. As far as tests go, I wouldn’t say that these are high quality tests that you would want to keep around for the lifetime of a project. But they’re exactly what you need to be able to refactor some opaque code into something maintainable. Once you get it to that state, it will be easier to write some high quality tests around the code, and you can begin to remove the scaffolding that Approval Tests initially provided.
As a bonus, here’s a neat trick that the author of Approval Tests came up with: Lets say you’re working on some terrible code and it uses a logger. You can mock out the logger and record every string the logger gets. For example, if you pass in “baz” as input the logger might say:
1 2 3 4 |
Starting the foo method Starting the bar method Ending the bar method Ending the foo method |
Approval Tests can record that the logger said this and then you can refactor. If you try again by passing in “baz” and the logger now says:
1 2 3 4 5 6 |
Starting the foo method Starting the bar method Ending the bar method Starting the bar method Ending the bar method Ending the foo method |
Oops… somewhere in your refactoring you changed some functionality. The
bar method is now being called multiple times when it used to be called only once (Approval Tests will highlight these changes so you don’t have to notice them on your own). You can either spend time to figure out why or simply revert your refactoring and try again. If you’ve been putting off testing your code because it’s too difficult to get started, then you should consider using Approval Tests. It lowers the barrier to entry and is a easy way to gain confidence in your automated tests.