When unit tests are better than acceptance tests

In my last post, I talked about how acceptance tests can be more important than unit tests. But clearly there is another side of the coin.

The conventional wisdom is that you should have more unit tests than acceptance tests. This is how I’ve done it in the past (on pretty much every project other than my current one).

A common scenario is a web application that uses an ORM for data access with as few stored procedures as possible. Because I’m using an ORM, my data layer has very little code. I’ll probably write a few basic unit tests and integration tests to test what data layer I have, and I’ll write integration tests to test the stored procs that I have (usually only for queries that need custom SQL).

My data layer primarily contains a really simple repository class that lets me do CRUD operations and get sort of IQueryable so that I can write LINQ queries. (If you’re using Rails, you don’t have to build any of that because it’s all there for you out of the box.) I don’t want my repository methods to have any concept of business logic or specific LINQ queries. Those belong in the business layer. The exception would be any stored procs that I have to have. I’m want to have a really thin data access layer and a fat business layer (yet another reason to use an ORM instead of having lots of SQL code in stored procs).

The business layer is going to contain the meat of the code. This is where I’m going to have a lot of unit tests. Because I kept my data layer so simple, I’m not going to have as many classes to stub out, and when I do, I’m stubbing out simple methods like Save() and Get(), which have no business logic in them.

I also have controllers, which take information from the business layer and return some sort of view model. I’ll write unit tests that verify that that translation happens correctly.

If I have some hardcore JavaScript, I’ll write unit tests for that. If it’s really simple stuff like, “when this radio button is clicked, disable this text box”, I don’t write tests for that. But when you build something that has more logic, you’ll want to test it.

At this point, I’ve tested pretty much everything very extensively. I could add some acceptance tests, which could help me communicate with the business and automate some QA testing. But at the same time, I’ve been on projects where I had excellent unit test coverage and no acceptance tests and it came out just fine. Now, that project was a two-person project with no QA team, so we just trusted our coding abilities and accepted the risk and things came out just fine. The point of saying this is not to say that you should fire your QA team, it just an example of how you can structure your code in a way that will allow you to unit test the code and get it right pretty much all the time.

This is just one example of one project. Your project might be different, with a different architecture, a different team, and a different business. You need to figure out what works best for you.