Testing with ExpectedObjects

The other day I read an interesting post about testing and a library that might help in some cases, its title is “Introducing the Expected Objects” library. I thought it might be useful and so I spent a spare evening writing some code to check whether is something that could be useful for my team.

The Problem

Imagine you are testing a complex object: multiple properties, graphs of objects, collections… and you want to test the outcome of some operation on it and you are using NUnit as your testing framework.
Which strategies are available?

Multiple Assertions

Most of the time, this is accomplished by using one or more assertions (watch it) that will check the values of certain properties. As the object is complex, the assertion might be complicated or I might not communicate correctly what we are trying to achieve.

IEqualityComparer

Another way of checking it is creating an instance with the members that are relevant to the test and providing a custom equality comparer to check just those values. This approach has some drawbacks:

  • it might no be easy to have the expected object in the desired state and in any case we are using a great deal of logic inside our test, which can lead to false positives
  • whenever the assertion fails, we have no useful feedback about what went wrong
  • the comparer has to be created ad-hoc and, as always, unless tested, needs to be taken as a source of false positives

Composite of constraints

This is probably your best choice as it is not too difficult to create something that communicates intent properly and the feedback when the assertion fails contains all sorts of useful information. The drawback lies in the amount of artifacts that one need to create in order to achieve the goals.

Another solution

Most of the time the composite of constraints is the best solution, but for simpler scenarios the extra work might not look appealing. After all the test is focusing in just a a subset of the properties of the actual object, isn’t there an easier/cheaper way?

And here is where ExpectedObjects can lay its helping hand. Amongst other features it allows checking the equality of instances of types that do not have to be the same type but have the same “shape” and values. Thus, one can create an anonymous object containing just the values needed and assert the actual objects against it.

In this example, complex is an instance of CustomWithCollection that it is pretty complex (although feasible to create, for the sake of the example). This instance might be returned by the method we are testing and we are only interested in its Name property and certain properties of its Addresses collection. An anonymous object is created with just the properties that are of interest for the test, and the Must.Match.Expected() magic (powered by ExpectedObjects and sprinkled with a bit of adaptation logic) does it job beautifully.

var complex = new CustomerWithCollection
{
Name = "name",
PhoneNumber = "number",
Addresses = new[]
{
new Address { AddressLineOne = "1_1", AddressLineTwo = "1_2", City = "city_1", State = "state_1", Zipcode = "zip_1"},
new Address { AddressLineOne = "2_1", AddressLineTwo = "2_2", City = "city_2", State = "state_2", Zipcode = "zip_2"}
}
};

var expected = new
{
Name = "name",
Addresses = new object[]
{
new { State = "state_1"},
new { Zipcode = "zip_2"}
}
};

Assert.That(complex, Must.Match.Expected(expected));

What happens when the expectations are not met? In this example, a pretty deep-buried value does not match the one occurring in the actual object. The assertion will fail and the failure is pretty descriptive:

var complex = new CustomerWithCollection
{
    Name = "name",
    PhoneNumber = "number",
    Addresses = new[]
    {
        new Address { AddressLineOne = "1_1", AddressLineTwo = "1_2", City = "city_1", State = "state_1", Zipcode = "zip_1"},
        new Address { AddressLineOne = "2_1", AddressLineTwo = "2_2", City = "city_2", State = "state_2", Zipcode = "zip_2"}
    }
};

var expected = new
{
    Name = "name",
    Addresses = new object[]
    {
        new { State = "state_1"},
        new { Zipcode = "notSameValue"}
    }
};

Assert.That(complex, Must.Match.Expected(expected));

Expected objects

How about refactoring of the actual object? Bad news is that you have a failing test for structural change reason (annoying). Good news is that your tests running in your CI process caught it straight away and it is easy to change. Even better is that some refactoring tools are pretty good in “guessing” the rename and suggest a solution.

Wow. Exactly what I Needed

Isn’t Open Source Software amazing? If you think so, go and get Testing.Commons.NUnit (or snatch it from NuGet)and you can start using this feature and some others straight away!

Daniel Gonzalez Garcia
Vertica A/S

Kategorier: Udvikling

Tagged as: , ,

Skriv et svar

Udfyld dine oplysninger nedenfor eller klik på et ikon for at logge ind:

WordPress.com Logo

Du kommenterer med din WordPress.com konto. Log Out / Skift )

Twitter picture

Du kommenterer med din Twitter konto. Log Out / Skift )

Facebook photo

Du kommenterer med din Facebook konto. Log Out / Skift )

Google+ photo

Du kommenterer med din Google+ konto. Log Out / Skift )

Connecting to %s