I've talked about unit testing a number of times in the past, however I often do so with the assumption that we have a shared understanding of what a unit test actually is.

A unit test is simply a test that ensures that a single class does what it is meant to without needing to cross classes boundaries in order to execute, with the exception of using mocks and stubs.  This is often represented using the ACID acronym, commonly talked used when referring to database transactions.:

  • Atomic
  • Consistent
  • Isolated
  • Durable

A test that verifies multiple pieces of functionality is not atomic.

A test that changes results based on external factors (such as time of day) is not consistent.

A test that hits a database, file system, network or even interacts with other business classes is not isolated.  Neither are tests that need to be run in a specific order.

A test that fails if a config files isn't set correctly, or if specific data isn't available or breaks when other classes in the application change (not including the class under test) is not durable.

It's a pretty simple way of thinking of things.

And just to be really clear a test written using a unit testing framework (NUnit, MSTest, xUnit, etc) isn't automatically a unit test either.

 

So does that mean we should only write tests to meet this criteria.  Not at all! Just don't call them "unit tests".  They are integration tests. And they are absolutely required when testing your application.  Unit testing only one part of the overall testing picture.

As a note, when I write tests I typically store unit tests and integration tests in separate assemblies to make it clear what type of tests are stored in each.  And when I do TDD I will quite happily use integration tests as a part of the TDD process - but only after I have already done as much as I can with unit tests.