What Is Not A Unit Test?
A few years ago, a programmer colleague nicely illustrated one difference between unit tests other automated tests: He unplugged the network cable from his computer and ran the unit test suite. Many tests that had previously passed now failed – they required network resources.
Those tests were not unit tests. They were integration and system tests.
Unit tests should not depend on Network I/O.
Why is this?
OK, let’s look at what we desire from unit tests:
Unit tests exist to validate the working of our code. We don’t need them to verify that the network is up, or that the database code is working as expected. Unit tests are concerned with our programming.
We want our unit tests to have these properties:
Unit tests should only fail when either the test code changes or the implementation code changes. That’s it. They should not fall over for spurious and temporary reasons. Unit tests are an extremely reliable measure as to whether our software works or not.
The more we rely on Network I/O and any code that is not ours (database, network, SDKs and libraries, remote services, file systems, configuration files) the further we are moving away from unit tests. Please note, though, that to a degree, we are always dependent on other code, e.g. our computer language and related frameworks.
Unit tests are meant to be fast. 1000+ unit tests should run in seconds. Accessing resources via a LAN or WAN is slow. System and integration tests run much slower. Depending on the number of tests, a system test run can take minutes to hours.
It is an excellent idea to group our (fast) unit tests separately from the (slow) system tests. We want to be able to run our unit tests all the time to detect broken functionality. On the other hand, integration and system tests that run for hours probably ought to be run once or twice a day.
Unit tests are finely-grained. They tend to involve a small group of collaborating classes or functions. On the other hand, system tests verify the working of whole coarse-grained system functions, traversing from the system entry points (UI or API) through the application business logic down to the service layer (database, remote services) and back up again. When a system test is failing, we may not have a good idea as to the cause of the problem: Is it a database problem? Have changes to our business logic caused the test to fail? Or is the failure situated in our presentation layer?
So to recap, other automated tests may require Network I/O but not unit tests.
Unit tests should be fast, robust, and finely-grained.
- Not connect to a database,
- Not connect to a remote service (or even a local service!),
- Not perform any Network I/O,
- Not even read from or write to the local file system.