Unit Test Naming Convention

Posted by: Steven Smith, on 10 Jan 2011 | View original | Bookmarked: 0 time(s)

Ive 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 didnt 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).

image

Test results can be grouped similarly:

image

Ive 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 youve bought into the idea that testing actually helps to improve the quality of the software you build, and youve 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 dont 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.


Advertisement
Free Agile Project Management Tool from Telerik
TeamPulse Community Edition helps your team effectively capture requirements, manage project plans, assign and track work, and most importantly, be continually connected with each other.
Category: Regex | Other Posts: View all posts by this blogger | Report as irrelevant | View bloggers stats | Views: 1168 | Hits: 32

News Categories

.NET | Agile | Ajax | Architecture | ASP.NET | BizTalk | C# | Certification | Data | DataGrid | DataSet | Debugger | DotNetNuke | Events | GridView | IIS | Indigo | JavaScript | Mobile | Mono | Patterns and Practices | Performance | Podcast | Refactor | Regex | Security | Sharepoint | Silverlight | Smart Client Applications | Software | SQL | VB.NET | Visual Studio | W3 | WCF | WinFx | WPF | WSE | XAML | XLinq | XML | XSD