A unit test is a way of testing the smallest piece of code that can be logically isolated in a software application. In most programming languages, that is a function, a subroutine, a method, or a property. The isolated part of the definition is important. In his book Working Effectively with Legacy Code, author Michael Feathers states that such tests are not unit tests when they rely on external systems. He writes, “If it talks to the database, it talks across the network, it touches the file system, it requires system configuration, or it can't be run at the same time as any other test."
Modern versions of unit testing can be found in frameworks like JUnit, or testing tools like TestComplete.Look a little further and you will find SUnit, the mother of all unit testing frameworks created by Kent Beck, and a reference in chapter 5 of The Art of Software Testing. Before that, it's mostly a mystery. We asked Jerry Weinberg about his experiences with unit testing -- "We did unit testing in 1956. As far as I knew, it was always done, as long as there were computers."
Regardless of when and where unit testing began, one thing is for sure. Unit testing is here to stay. Let's look at some more practical aspects of unit testing.
What do unit tests look like?
A unit can be almost anything you want it to be -- a line of code, a method, or a class. Generally though, smaller is better. Smaller unit tests give you a much more granular view of how your code is performing. There is also the practical aspect that when you test very small units, your tests can be run fast; like a thousand tests in a second fast.
Consider this sample code:
def divider (a, b)
return a/b
end
Using Ruby, those small tests might look something like this:
class smallTest < MiniTest::Unit::testCase
def tiny_test
@a=9
@b=3
assert_equal(3, divider(a, b))
end
end
This example is overly simple, but it gives you an idea of what we mean by small. Small unit tests also have the benefit of making it harder to cross systems -- from code into a database, or third-party system. Strictly speaking, there isn't anything wrong with crossing systems, but there are consequences, such as gradually slowing your tests.
Learn More About Automated Testing
Who should create unit tests?
In his book, Real-Time Business Systems, Robert V. Head says, "Frequently, unit testing is considered part of the programming phase, with the person that wrote the program...unit testing". That isn't because programmers hold the secret sauce to unit testing, it's because it makes sense. The programmer who wrote the production code will likely know how to access the parts that can be tested easily and how to mock objects that can't be accessed otherwise. It's a time trade-off.
Other times, someone will come in after the fact and write tests to help create safeguards while they refactor or further develop that area of the code base.
How can you use unit tests?
Hammers are great tools and can help you with a lot of different jobs -- opening car windows or turning off alarm clocks. But, they are especially well suited to putting nails through hard surfaces. Unit tests are similar. They can do lots of different things, but they should probably only do a few.
Test driven development
Test Driven Development, or TDD, is a code design technique where the programmer writes a test before any production code and then writes the code that will make that test pass. The idea is that with a tiny bit of assurance from that initial test, the programmer can feel free to refactor and refactor some more to get the cleanest code they know how to write. The idea is simple, but like most simple things, the execution is hard. TDD requires a completely different mindset from what most people are used to and the tenacity to deal with a learning curve that may slow you down at first.
Checking your work
TDD isn't new, but at this point, it is still mostly for the go-getters. The rest of us are checking our work. Writing unit tests after you have written the production code may be a more traditional way of doing it, but it is no less useful. It's also something you're familiar with if you have been in a math class in the past ten years.
After your work is checked and it is clear that the code is doing what you think it is doing, the value of the unit tests changes a little bit. Tests that can be easily run with every build of your product act as change detection notifying you when code changes in unexpected ways.
Code documentation
Code documentation is a drag, and it shows, mostly by how little code documentation gets written. Unit testing can make the documentation burden a little easier by encouraging better coding practices and also leaving behind pieces of code that describe what your product is doing. Rather than having to constantly feed the documentation beast with code changes, you'll be updating a system of checks that is working for you.
When should you avoid unit testing?
There are a few uses of unit testing that you will want to avoid when possible. Creating integration tests that cross system borders and touch databases or third-party systems can be done, but this quickly results in a test suite that takes longer and longer to run with each added test. There are plenty of test frameworks out there that specialize in higher-level testing. If you want to test larger pieces of your product at a time, you might want to investigate those other frameworks.
One other risky area is end-to-end tests. These usually require careful ordering, dependencies on other tests, and careful setup to get your system in a special 'test ready' state. Much like integration testing, there are plenty of tools to choose from made just for this purpose.
You definitely can do these things with unit frameworks, but it might quickly become more work than it is worth.
Common problems when unit testing
The most common problems we have with unit testing usually aren't technical problems.
People have a hard time adapting to new ways of working after spending time in an environment where unit testing amounts to loading up the latest build and seeing whether it starts or not. To combat this, find one person who is interested in unit testing and will commit to staying up-to-date with best practices. That person can be your champion to help build a case for the usefulness of unit testing and help to spread the idea through the dev organization through their successes.
There is also a myth that says if testing is good, then more testing is better. Smart testing is good and will help to create a valuable, stable product, but smart testing doesn't always end in an impressive number of tests. Smart unit testing delivers relevant information about your software quickly and often.
We've covered some of the basics of unit testing, and given you some ways to talk about them with your team.
Start Unit Testing Now With a TestComplete Free Trial