Tuesday 6 October 2015

Using the TestCaseSource attribute in NUnit

I’ve used NUnit for the last few years but I only recently discovered the TestCaseSource attribute which is very useful in certain circumstances.

The scenario

Imagine you have a DeviceInformation class. It’s job is to take a user agent, parse it and provide information about the device. The class could look something like this:
public class DeviceInformation
{
    public bool IsDesktop { get; private set; }
    public bool IsMobile { get; private set; }
    public bool IsTablet { get; private set; }
    public string Manufacturer { get; private set; }

    public DeviceInformation(string userAgent)
    {
        // Some code here which sets the class properties
    }
}
One way to attack this is to create a bunch of user agents and use the TestCase attribute to confirm that multiple user agents return the same result.
private const string USER_AGENT_IPHONE_4 = "...";
private const string USER_AGENT_GALAXY_S5 = "...";
private const string USER_AGENT_LG_G4 = "...";
private const string USER_AGENT_GALAXY_TAB = "...";

[TestCase(USER_AGENT_IPHONE_4)]
[TestCase(USER_AGENT_GALAXY_S5)]
[TestCase(USER_AGENT_LG_G4)]
public void IsMobileDevice_UserAgentIsMobile_ReturnsTrue(string userAgent)
{
    Assert.IsTrue(new DeviceInformation(userAgent).IsMobile);
}

[TestCase(USER_AGENT_GALAXY_TAB)]
[TestCase(USER_AGENT_GALAXY_S5)]
[TestCase(USER_AGENT_LG_G4)]
public void IsAndroidDevice_UserAgentIsAndroid_ReturnsAndroid(string userAgent)
 {
     Assert.That(new DeviceInformation(userAgent).Manufacturer, Is.EqualTo("Android"));
 }

// More tests to cover the IsDesktop, IsTablet and Manufacturer properties here
This is a trivial example and there are already quite a few user agents. You can see that if I were to thoroughly unit test DeviceInformation I would need a lot more user agents and a lot more tests. As the number of users agents increased the number of attributes on each test would increase and the tests would become more difficult to maintain. Each time a user agent was added I’d need to scan every single test and make sure new attributes were added where appropriate.

Using the TestCaseSource attribute

From the NUnit documentation:
TestCaseSourceAttribute is used on a parameterized test method to identify the property, method or field that will provide the required arguments.
This means you can use a property, method or field to hold all of the user agent strings for a particular test rather than specify each one in it’s own attribute. Here I’ve used arrays to organise user agents into groups:
readonly string[] mobileUserAgents =
{
    USER_AGENT_IPHONE_4,
    USER_AGENT_GALAXY_S5,
    USER_AGENT_LG_G4
};

readonly string[] androidUserAgents =
{
    USER_AGENT_GALAXY_TAB,
    USER_AGENT_GALAXY_S5,
    USER_AGENT_LG_G4
};

[Test, TestCaseSource("mobileUserAgents")]
public void IsMobileDevice_UserAgentIsMobile_ReturnsTrue(string userAgent)
{
    Assert.IsTrue(new DeviceInformation(userAgent).IsMobile);
}

[Test, TestCaseSource("androidUserAgents")]
public void IsAndroidDevice_UserAgentIsAndroid_ReturnsAndroid(string userAgent)
{
    Assert.That(new DeviceInformation(userAgent).Manufacturer, Is.EqualTo("Android"));
}
Now each test only has one attribute, much better. Also, to keep the snippet short I’ve only added two groups of user agents, but for a thorough test I’d add a lot more. For example appleUserAgents, tabletUserAgents, desktopUserAgents, backBerryUserAgents, windowsPhoneUserAgents etc. Now when you want to test a new user agent you simply create a new user agent variable and add it to the appropriate arrays. The is no need to change individual tests. Easy.

Sunday 4 October 2015

What is Command Query Separation?

What is Command Query Separation (CQS)? It’s a principle created by Bertrand Meyer which states that any operation in code should be one of two types; a query or a command, but not both.
  • Query. This isn’t a database term, it simply means that the operation should return some data and not have any side effects. Repeated calls to a query should return exactly the same result
  • Command. This is an operation that takes some action, it has side effects, it can change your programme state
For example:
public ShoppingCart GetShoppingCart();

public void AddItemToShoppingCart(Item item);
GetShoppingCart() is a query, because the signature shows it returns data. AddItemToShoppingCart() is a command because it returns void.

Is CQS the same as CQRS?

No. They share some terminology but CQS is a programming principle that applies to the methods on an object. Command Query Responsibility Segregation on the other hand is pattern that splits queries and commands into separate models.

Why is CQS useful?

I had a lightbulb moment when I read a chapter of Code Complete 2 entitled “Conquer Complexity”. It lists numerous good practices programmers use including writing short methods, writing small classes, using meaningful variable and class names, avoiding deep inheritance hierarchies and breaking up larger systems into smaller sub-systems. The author, Steve McConnell, finishes the chapter with the following:
“A primary goal of software design and construction is conquering complexity. The motivation behind many programming practices is to reduce a program’s complexity”
In hindsight I feel a bit stupid. I hadn’t realised that all the these familiar principles served the same purpose, to reduce complexity.
CQS wasn’t listed in that chapter, but it’s no different, it helps reduce complexity. If a code base strictly follows CQS then you can trust an interface without digging into the implementation. If a method returns a value, it’s a query and can be called safe in the knowledge it won’t change anything, no matter how often it’s called. If a method returns void, it’s a command and more care is required.