Unit Testing: Still Necessary. Still Faster by Gregg Bolinger on Jun 02, 2014

There has been an interesting trend in the last couple of months based around the idea that Unit Testing is not as important and we, as developers and testers, should be focusing more on integration testing. Take for example this article titled Test-induced Design Damage. This article states that:

“One conclusion of this is that I think it’s a mistake to try to unit test controllers…Controllers are meant to be integration tested, not unit tested.”

The author is really talking about the Rails framework here, but I think it is important to focus on this misconception without worrying too much about the driving technology. Before I dive too deeply into my thoughts on this topic I feel like I should define some terminology so that my point might come across with more clarity.

(M)odel (V)iew (C)ontroller

MVC is a design pattern that has been around since the 1970’s and is believed to have made its first appearance in Smalltalk-80. The idea behind MVC is based around a separation of concerns. Speaking very generally here because MVC has been redefined over and over, the Model is responsible for managing the data, the View is responsible for presenting that data, and the Controller is the broker. Most modern web application frameworks are built around the MVC pattern.

Unit Test

Unit Testing is the method by which an individual unit of code is tested. Usually this unit of code is a small amount of business logic or an algorithm encapsulated within an individual method or function. Take, for example, the following code:

A Unit Test for the add() method might look like this:

Integration Test

An Integration Test is the method by which several units of code that work together are tested using a single point of entry. You are testing to ensure that your software is integrating properly between its various modules or services. This, in a very simplistic example, might look like this:

Note that in the above code there are several units of code being called from the saveTransaction() method. Testing the saveTransaction() method would be considered an Integration Test because you are testing that the database was updated correctly, the email was sent correctly, and the logging worked as expected, whether that is to a database or to a file.

Why Unit Test Controllers?

A well written Controller is anemic. By that I mean it generally contains only enough logic to handle a request and send a response. All the business logic should be handled by some sort of service layer or business layer in your software applications. Since well written Controllers should contain a minimal amount of code, the idea that Unit Testing them is a waste of time might seem perfectly valid. Especially when you consider today’s modern frameworks. A lot of the Controller code should be tested by the developers who maintain the framework, right? Let’s look at this simple Grails controller as an example:

Lines 3 and 4 are clearly the meat of this Controller. Line 3 simply gets the user from the database. Line 4 renders the user as the model to a view called show. Nothing too special here and in fact, both lines rely solely on an API provided by Grails which should already be tested. The code above is very common for Grails 2.2.x. Let’s look at the same code for the latest version of Grails.

We’ve replaced the render method with the respond method. The respond method is different than render in that where render relies on the developer to specify the returned content type (HTML by default), the respond method attempts to return the most appropriate type for the requested content type (specified by either the Accept header or file extension). That’s a significant change. Without any tests, you won’t know if upgrading your application to the latest version of the framework is going to break in production or not. Does Grails still support the render method? What are the ramifications for changing it to respond? Without any tests, this is incredibly dangerous, even for this simple Controller. But why Unit Testing? Won’t an Integration Test tell us the same thing? Won’t an Integration Test fail the same way? Aren’t computers fast enough that Integration Testing is not a big deal anymore? I have a MacBook Pro 2.6 GHz Intel i7 with 8GB of RAM. Running a single Integration Test in Grails takes 34 seconds just to get to the point to where it will run the test. 34 seconds and the test hasn’t even started yet! We can blame some of that on Grails and there are some ways to shave off a few seconds but generally speaking, that’s a long time on my really fast computer. A Unit Test, on the other hand, is finished in 10 seconds or less. As in, the test has finished and has written out reports. Unit Tests generally require less setup and less data. Mocking libraries today are simple and powerful so there is no need to worry about making calls to services that are auxiliary to what you’re really trying to test; that the Controller took the request and provided an expected response without errors. Having a test process possibly hundreds of lines of algorithms and database calls just to find that out is a waste of time. At the end of the day, we just want software to be fully tested. If that means Integration Tests for you and you have a high confidence that your software is as bug free as you can possibly ensure, then that’s great. But Unit Testing still has its place, especially with regards to Controllers, contrary to popular opinion. Unit Testing is still faster and will generally catch those pesky bugs from upgrades a lot quicker than an Integration Test.