Unit Test Naming Convention
I’ve been writing tests and unit tests for quite a while, and naturally my personal preference for naming them has evolved somewhat with time. Initially, I didn’t really know what I was doing and the default organization tended to be something like “given a class, Customer, all of the tests will go into a class called CustomerTests.” This turned out, for me at least, to be less than ideal. Later I learned more about BDD and specifications and I decided I could apply some of the same context and scenario information to my test organization as well. Thus, I began striving to write my test classes such that each one described a particular scenario, and each test described a particular variation within that scenario (e.g. happy path, sad path, etc.).
By way of example, consider an e-commerce module that includes a pricing calculator. One particular scenario for the pricing calculator might be to deal with a “preferred customer” who gets a special discount. Others might be for regular customers, and still others for dealing with high volume orders or wholesale customers. If I were to name my classes the way I did when I first started writing tests, I might have a PricingCalculatorTests class, which in turn would have many dozens of tests in it. However, using my current preference, I might have classes like PricingCalculatorGivenNormalCustomerShould, PricingCalculatorGivenPreferredCustomerShould, PricingCalculatorGivenWholesaleCustomerShould, etc. If I find that there are a great many such classes, then of course you can use namespaces and folders to keep things well organized.
When using this style of test naming, the Test View in Visual Studio becomes very easy to read. Simply change the default Group By to Class Name (or if you are putting scenario information into your namespace, consider using Full Class Name).

Test results can be grouped similarly:

I’ve written up a small sample showing this naming convention – download the sample project here. Below you can see one of the test classes in its entirety as well as the System Under Test, the Pricing Calculator.
PricingCalculatorGivenRegularCustomerShould.cs – Test Class
using System;
using Core;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UnitTests
{
[TestClass]
public class PricingCalculatorGivenRegularCustomerShould
{
private Customer _customer;
private PricingCalculator _pricingCalculator;
[TestInitialize]
public void Setup()
{
_pricingCalculator = new PricingCalculator();
_customer = new Customer {IsPreferred = false};
}
[TestMethod]
public void ReturnPriceTimesQuantityGivenQuantityGreaterThanOne()
{
// Arrange
int units = 1;
decimal unitPrice = 2.50m;
// Act
decimal calculatedPrice = _pricingCalculator.Calculate(units, _customer, unitPrice);
// Assert
decimal expectedPrice = unitPrice*units;
Assert.AreEqual(expectedPrice, calculatedPrice);
}
[TestMethod]
public void ReturnZeroGivenQuantityZero()
{
// Arrange
int units = 0;
decimal unitPrice = 2.50m;
// Act
decimal calculatedPrice = _pricingCalculator.Calculate(units, _customer, unitPrice);
// Assert
decimal expectedPrice = 0m;
Assert.AreEqual(expectedPrice, calculatedPrice);
}
[TestMethod]
[ExpectedException(typeof (ArgumentOutOfRangeException))]
public void ThrowArgumentOutOfRangeExceptionGivenQuantityLessThanZero()
{
// Arrange
int units = -1;
decimal unitPrice = 2.50m;
// Act
decimal calculatedPrice = _pricingCalculator.Calculate(units, _customer, unitPrice);
// Assert
Assert.Fail("Should have thrown exception.");
}
}
}
PricingCalculator.cs – System Under Test
using System;
namespace Core
{
public class PricingCalculator
{
public const decimal PreferredCustomerDiscount = 0.2m;
public decimal Calculate(int units, Customer customer, decimal unitPrice)
{
decimal price = units*unitPrice;
if (customer.IsPreferred)
{
return price*(1 - PreferredCustomerDiscount);
}
if (units < 0)
{
throw new ArgumentOutOfRangeException("units", "Units must be zero or greater.");
}
return price;
}
}
}
Summary
If you’ve bought into the idea that testing actually helps to improve the quality of the software you build, and you’ve further realized that automated testing is far more cost effective than manual testing, then it follows that you will need to organize your tests in some fashion. I have personally found the above technique to be useful in doing so on projects I work on. I don’t suggest that this technique will work everywhere for everyone, or that it is the ultimate such technique (especially given that it's only the latest in a series of different conventions I have adopted). However, it remains my current favored approach because it produces easily understood tests whose classes tend to follow the Single Responsibility Principle and Open/Closed Principle, as well as producing output that is easily understood by everyone on the development team as well as by business stakeholders.