Michael’s rules on what a unit test is seem overly draconian to some (not being able to touch the filesystem for example 99% of the time I’d agree, but if I’m testing my FileConfiguration class, what the hell am I supposed to do?) and despite many other people attempting to define what a unit test is, Cedric’s take on it comes the closest to my own understanding of what a unit test is:
…a unit test is traditionally defined as a set of test that exercises a single class in isolation of all others.
Cedric then goes on to say that 90% of the tests he sees written with JUnit are not unit tests. I for one would be wary of working on those codebases. He also states that he doesn’t care if the test he writes is a unit or functional test which immediately makes me worry about working on his codebase.
The point that gets missed here is that Unit and Functional tests are not different because of how they work, how long they take or the tools required to make them work, but they are different because they fulfill different roles in development.
Unit tests, because they focus on testing one class and one class only, make it much easier to create highly-focused loosely coupled code, as you create and test a class in isolation of other code. As you have good test coverage at a single class level, you can then safely refactor the class and know you haven’t changed the behavior of the unit. As you are writing code and testing at a small level, you can commit your code more frequently, enabling frequent, smaller-scale integration. If you are testing at a class level, the test themselves become a living document detailing how your code works.
Functional tests are supposed to test slices through your system – from UI to back-end and back if possible. You are asserting that your system conforms to the behavior expected by your users.
Unit tests tend to be fast because they limit the code they test. Functional tests tend to be slow, because they test more code, and also interact with slow components (e.g. databases, browsers, networks etc) but their speed doesn’t define what type of test they are.
Often there is the need to separate fast tests from slow tests – and TestNG’s categorisation of tests is perhaps the first feature of the TestNG that has interested me. But the categorisation is done in order to define fast feedback cycles (e.g. run a quick build on checkin, and longer build on the hour, everyday etc – see Speeding up the build and build pipelining for more details) this should not be used to confuse functional and unit tests. Developers need to understand the different requirements for, and benefits of, these two different types of tests.