What exactly is a "unit" in unit testing? 
Tags: solid, unittesting
Published: 2017-02-13 12:01:26

---
title: What exactly is a "unit" in unit testing? 
published: true
description: What is a unit in unit testing? There's no clear definition, but in this post I'll take you through the popular definitions and end up describing a new one.
cover_image: https://i0.wp.com/www.blinkingcaret.com/wp-content/uploads/2016/04/paths-through-a-labirinth_thumb.jpg?resize=392%2C252
tags: solid, unit-testing
canonical_url: http://www.blinkingcaret.com/2016/04/27/what-exactly-is-a-unit-in-unit-testing/
---

This should be an easy question to answer, right? Turns out that there are several definitions of unit testing, and even though they are similar, they are also different enough that answering this question is difficult.

Let's look at some examples. Form [Wikipedia][wikipedia unit testing]:

> In computer programming, unit testing is a software testing method by which individual units of source code, sets of one or more computer program modules together with associated control data, usage procedures, and operating procedures, are tested to determine whether they are fit for use. Intuitively, one can view a unit as the smallest testable part of an application. In procedural programming, a unit could be an entire module, but it is more commonly an individual function or procedure. In object-oriented programming, a unit is often an entire interface, such as a class, but could be an individual method. 

So, according to Wikipedia a unit can be "an entire module", "an individual function", "an entire interface/class", but also "an individual method". 

From [MSDN][unit testing msdn]:

>The primary goal of unit testing is to take the smallest piece of testable software in the application, isolate it from the remainder of the code, and determine whether it behaves exactly as you expect...  

A little less vague, a unit here is described as the "smallest piece of testable software in the application". This still leaves room for debate.

Martin Fowler acknowledges [that unit testing (and consequently a unit) is not tightly defined][unit testing martin fowler], however finds these common elements in definitions:

> ...Firstly there is a notion that unit tests are low-level, focusing on a small part of the software system. Secondly unit tests are usually written these days by the programmers themselves using their regular tools - the only difference being the use of some sort of unit testing framework. Thirdly unit tests are expected to be significantly faster than other kinds of tests.

One of my favourite definitions is from [Roy Osherove's _The Art of Unit Testing_ book][art of unit testing] where Unit testing is defined as:

> A unit test is an automated piece of code that invokes the unit of work being tested, and then checks some assumptions about a single end result of that unit. A unit test is almost always written using a unit testing framework. It can be written easily and runs quickly. It's trustworthy, readable, and maintainable. It's consistent in its results as long as production code hasn't changed.

There's also the definition of "unit of work":

> A unit of work is the sum of actions that take place between the invocation of a public method in the system and a single noticeable end result by a test of that system.

That end result is the method returning a value, some public state of the class changing or the public method being tested invoking another method in a dependency.

I really like this definition, however, I find the choice of using the term "unit of work" unnecessary, especially because it is a loaded term. For example, when discussing Object Relations Mappers (ORMs) the term ["unit of work"][unit of work pattern] has a completely different (and well established) meaning that is misleading in this context. 

### The "unit"

Can we agree that when we are writing a unit test we call a single method on the class we are testing? If so, then why can't we consider a unit to be the _logical path_ (path that the execution of the code takes) through that method given our initial setup of the test.

The tests need to be deterministic, so for the a given setup the logical path will always be the same. 

Let me show you an example using an `Account` class and a `Withdraw` method. If there are enough funds, the amount withdrawn is taken from the account's balance, if not an `InsuficientFundsException` is thrown.

![Example of a withdraw method with 2 logic paths][Example of a withdraw method with 2 logic paths]

There are two possible logical paths through the `Withdraw` method, one where there are sufficient funds, and another were there aren't. If we want to be thorough, we should write a test for each.

### A little taste of test first development

Let's have a look at how this definition works while we write the `Deposit` method for our account. And let's do it test first.

For the first test we want to make sure that the balance gets updated when we make a deposit of a positive value, here's the test (I'm using [NUnit][nunit]):

![deposit positive amount test][deposit positive amount test]

And here's the implementation:

![deposit positive amount code][deposit positive amount code]

If the caller specifies a negative amount we want to throw an `InvalidOperationException`. Here's the test for that:

![deposit negative amount test][deposit negative amount test]

And here's the new implementation of the `Deposit` method:

![deposit negative amount code][deposit negative amount code]

We can see that up until now we have a test per logic path. We can add an extra test to cover the case where the amount is zero. However, I'd argue that that test exercises the same logical path through the code (unit) than the positive amount test (however, no harm will come in having that extra test).

If we want the method to behave differently when the amount is zero, then we'd have to add another if statement, and that would produce another possible logical path through the method, for which we could write another unit test.

You might be thinking these examples are super simple. How would something more complex, where there are other classes/dependencies involved fair? Does this notion of a unit being a logical path through the code hold?

Imagine that our `Deposit` method has this requirement of alerting the fraud department if the deposit looks suspicious. Let's write our test for that, starting with a "suspicious" deposit (I'm using [moq][moq] as my [isolation framework][fakes mocks and stubs]):

![suspicious deposit test][suspicious deposit test]

And now the test for when the deposit isn't suspicious:

![non suspicious deposit test][non suspicious deposit test]

And the new implementation of the `Deposit` method:

![deposit method with fraud detection][deposit method with fraud detection]

You've probably noticed that I added a few dependencies (`IFraudDetectionService` and `INotificationService`). We'll get to that. But first, what happens to the tests we previously had?

We have to adjust them so that they take into account the new dependencies, but should we keep all of them? Maybe we can drop the `Deposit_PostiveAmount_AdjustBalance` test.

If we look at all the possible logical paths through the `Deposit` method we can see that the there's no way that that test fails in isolation (path 2). If the balance is not updated correctly, both `Deposit_SuspiciousAmount_UpdatesBalanceAndSendsEmailToFraudDeparment` and `Deposit_NonSuspiciousAmount_UpdatesBalanceAndDoesNotSendsEmailToFraudDeparment` fail.

![annotated deposit method with logical paths][annotated deposit method with logical paths]

On the other hand, one can make the argument that we should have all tests, one for when the amount is negative, one that only asserts that the balance is updated correctly, another that verifies that the notification service is called when the deposit is suspicious, and another verifies that the notification service is not invoked when a deposit is not suspicious.

If we want that our definition of unit takes this into account, we can say that a unit is a **verifiable change that occurs in a logical path through a method**. That can be a change of internal state that is externally visible (e.g. the Account's Balance), a method invocation in a dependency (e.g. verify that the notification service was called) or the return value of the method.

The advantage of doing this is that it is easier to figure out what is wrong just by looking at the name of the failing test.

One thing you might have noticed is that this idea of logical path is very similar to a measure of software metric named [Cyclomatic Complexity][cyclomatic complexity]. A method's cyclomatic complexity is "the number of linearly independent paths through the code". In fact, right now, as I read the Wikipedia entry, I've just noticed that author the Cyclomatic complexity metric (Thomas McCabe) had this exact same idea (one test per logical path) as a testing strategy in 1996 (way before unit testing was popular). It is named [basis path testing][basis path testing article].

### The dependencies

This is a bit of an aside, but you should have noticed that I used interfaces so that I did not have to specify a specific criteria for when a deposit is considered suspicious, or how the "fraud department" is notified.

This not only made the code easier to test, it also has the advantage of isolating the `Account` class from changes in the criteria used to determine if a deposit is suspicious or how the notifications should be performed.

I brought this up just to mention that if you write the tests first you'll have these problems in mind, you'll want to write your code so that it is easy to test. You will feel compelled to write small focused methods, and be very mindful to what does and doesn't belong in a class and should be considered a dependency.

Also, you should be in full control of the code that executes through the logical path you are testing. For example, in `Deposit_SuspiciousAmount_UpdatesBalanceAndSendsEmailToFraudDeparment` I used [moq][moq] to create a [stub][fakes mocks and stubs] of the `IFraudDetectionService`  interface that always returns true when `IsDepositSuspicious` is called. 

Say the implementation of that dependency made a call to a database or some other service over the network. That would make that test be considered an **integration** test. However, I'd argue that even if no database call was made, or any service called, you should still use the isolation framework and create the stub. It removes uncertainty. When the test fails and you are in full control of what was executed, you don't have to guess what went wrong.


[junit website]: http://junit.org
[origin of junit video]: https://www.youtube.com/watch?v=1zaCvLVU70o
[wikipedia unit testing]: https://en.wikipedia.org/wiki/Unit_testing
[unit testing msdn]: https://msdn.microsoft.com/en-us/library/aa292197(v=vs.71).aspx
[unit testing martin fowler]: http://martinfowler.com/bliki/UnitTest.html
[art of unit testing]: https://www.manning.com/books/the-art-of-unit-testing-second-edition
[Example of a withdraw method with 2 logic paths]: https://www.blinkingcaret.com/wp-content/uploads/2016/04/Withdraw-annotated.png
[unit of work pattern]: http://martinfowler.com/eaaCatalog/unitOfWork.html
[nunit]: http://nunit.org/
[deposit positive amount test]: https://www.blinkingcaret.com/wp-content/uploads/2016/04/Deposit_PositiveAmount_Test.png
[deposit positive amount code]: https://www.blinkingcaret.com/wp-content/uploads/2016/04/Deposit_PositiveAmount.png
[deposit negative amount test]: https://www.blinkingcaret.com/wp-content/uploads/2016/04/Deposit_NegativeAmount_Test.png
[deposit negative amount code]: https://www.blinkingcaret.com/wp-content/uploads/2016/04/Deposit_NegativeAmount.png
[suspicious deposit test]: https://www.blinkingcaret.com/wp-content/uploads/2016/04/Deposit_SuspiciousAmountTest.png
[non suspicious deposit test]: https://www.blinkingcaret.com/wp-content/uploads/2016/04/Deposit_NonSuspiciousAmountTest.png
[deposit method with fraud detection]: https://www.blinkingcaret.com/wp-content/uploads/2016/04/Deposit_FraudDetection_Code.png
[annotated deposit method with logical paths]: https://www.blinkingcaret.com/wp-content/uploads/2016/04/Deposit_FraudDetection_Code_annotated.png
[moq]: https://github.com/Moq/moq4
[fakes mocks and stubs]: http://www.blinkingcaret.com/2012/11/20/interaction-testing-fakes-mocks-and-stubs/ 
[cyclomatic complexity]: https://en.wikipedia.org/wiki/Cyclomatic_complexity
[basis path testing article]: http://www.mccabe.com/pdf/mccabe-nist235r.pdf
[multiple paths one highlighted]: https://www.blinkingcaret.com/wp-content/uploads/2016/04/paths-through-a-labirinth.jpg