There are some topics that are near and dear to the hearts of all developers, and one is test driven development. Test driven development (often shortened to TDD) is a workflow about how to write code.
New features are added to web applications typically in an iterative manner. What that means is that programmers minimize the time between writing a single line of code and determining if the line of code works. That means most developers will not write hundreds of lines of code before checking if it works in a web browser.
Instead, they’ll usually write a couple lines of code, return to the web browser to make sure the sub-feature works, then move on to the next small sub-feature. Biting off very small pieces that can be quickly verified for functionality is pretty normal. Programmers, like ordinary people, are prone to typos, which result in error messages in the programs that they’re working on.
By working on small things, verifying they work, then moving on to the next thing, you prevent dozens of problems from piling up and making your application completely broken and hard to fix. This is what it means to “work in an iterative way.”
Other things can be built in an iterative manner, too. This blog post was, for instance. Although I would love to tell you that I wrote what you’re reading from top to bottom, typing at full speed, I didn’t. Instead, I wrote each sentence one at a time. After re-reading some paragraphs, I noticed that some sentences came out poorly, so I rewrote them. The process involved one small change after another, and ultimately led to this finished product.
All software is written in this iterative way. That means every programmer will write some code, then check that their code works shortly afterward.
There are two ways you can make sure your code does what you think it should.
The simplest way to do this is to just manually check to see if it works. If you write a few lines of code to add a button to a page, you could just reload the page and look at it. If you see a button on the page, you know you’ve successfully added one. If you don’t, you can go back to the code to figure out what you need to do to get the button on the page.
Enter: Automated Software Tests
Automated software tests are a series of short programs that make sure your application is working the way that it should. These programs will trigger the code in your application and check that your program does what it is supposed to do. If the feature doesn’t work, it will show the programmer an error message.
Having automated software tests is important if you’re working on a team of developers. Since a codebase can be very large, you likely won’t know in depth how every single feature works. You’ll only be familiar with the areas of code you worked on. This makes it easy for a developer to accidentally break another developer’s feature simply because they don’t know that the feature is supposed to exist.
They say ignorance is bliss, but whoever said that hasn’t talked to an angry user who saw an error message on their application. As developers, we want to be notified as soon as we break the application (think: the minute we write the code that breaks it). That means our tests should be easy to run. As a developer, it is also your job to write a test that will fail if someone breaks your feature. If you don’t, you can’t blame someone else for undoing your feature in the future… they might not have even known the feature you built exists in the application at all– and how could they be expected to?
But now, if we include writing software tests in the process of building applications, it could look like this:
- Step #1: Write the feature
- Step #2: Test that it works in the web browser
- Step #3: Write an automated test that will fail if the feature doesn’t work
But, Step #2 and #3 are redundant. You really don’t need to test that your feature works in the web browser if you have a test that will fail if the code wasn’t implemented properly.
This frees us up to think about if we could have written the feature in a better way. Maybe with less lines of code, or more efficient code, or with code that makes more sense. The process of rewriting working code is called refactoring. And that’s often what people who write tests first will do immediately after getting their code to work.
The upside to this approach is that we have a program to ensure that the feature still works. That means we can just run the program that tests the code to make sure it continues to work. (We won’t need to click around in a web browser; our program will be enough).
The full flow becomes:
- Step #1: Write a failing test
- Step #2: Make it pass
- Step #3: Refactor
Developers call this process a “Red/Green/Refactor Cycle.” It is actually faster to do this than to click around in a web browser (eventually you can write code faster than you can click around).
You may be wondering, do people write automated software tests that fail before they actually write the code for the feature in practice? Although not everyone writes code using this “Red/Green/Refactor” methodology, a high percentage of Ruby on Rails developers do.
That’s everything you need to know about how automated software tests work in theory. Let’s talk about the tools of the trade used by developers who practice TDD.
rspec vs. Test::Unit
There are two different programs that are generally used to write automated software tests for Ruby on Rails applications. One is rspec, and the other is Test::Unit. People are usually pretty opinionated on why the one they use is the best (both are frequently used).
Test::Unit is the original test suite. It’s the first testing tool for writing ruby programs using TDD. The following projects use Test::Unit:
- Ruby on Rails
- The ruby language itself
- Some companies, like Basecamp
The code you need to write in order to write unit tests in Test::Unit looks close to the code you write in your ruby application.
Test::Unit is part of Ruby’s Standard Library, which means if you’re using the ruby programming language, you can start using Test::Unit without having to install any other programs into your application. Also, if you use Ruby on Rails, your application will by default be hooked up with blank tests using this framework.
rspec is a BDD test suite. BDD is short for “Behavior Driven Development,” which means that when you’re writing the test for yourself as a developer, you also take into account the behavior that’s expected of the user.
What does that actually mean? The code that you write with rspec looks a bit closer to a plain English specification (or spec for short) for the feature– how it should behave.
Unlike Test::Unit, rspec isn’t built into the language’s Standard Library, which means if you want to use this tool, you’ll need to install an external program (these programs are called ruby gems) to your application before you can start using it.
Although both tools are great programs, you need to choose to use one or the other. You cannot use both within the same project. Since programmers spend a lot of time writing these automated tests, the debate between rspec vs. Test::Unit gets a lot of passionate responses for both sides.
In fact, the creator of Ruby on Rails, David Heinemeier Hansson (DHH) publicly bashed rspec on Twitter back in 2011.
As for my personal opinion, I prefer Test::Unit. I like that it’s built into the language itself (you don’t need to install external resources to your application to use it) and I find it a lot simpler to use.
But, many entry-level job postings list rspec as a technology they expect candidates to be familiar with. Because rspec is commonly used in the industry, if you’re looking to switch careers, learning how to write tests in rspec will help prepare you for the job.
There is also nearly a 5:1 ratio of rspec to Test::Unit examples on the internet, so it makes sense when you’re starting out to learn and use rspec.
And while my personal projects all use Test::Unit, for beginners starting out who are looking to switch careers and become web developers, I highly suggest learning rspec.
The most important thing you should take away from all of this is that writing tests is important. At the end of the day, the tool you use to write the test (rspec vs. Test::Unit) is only a detail you need to decide that ultimately isn’t too important.
So don’t sweat the decision. Know that once you learn how to use one tool to write your code using a TDD process, learning the other tool is something that you can do in a day or so. Don’t get too caught up in the TDD flamewar.