C# 7 Tuple Better Test Assertion
Recently I read C# In Depth 4.0 where I met the new Tuple design in C# 7. It is really a cool feature. Beside the syntax sugar, it offers capacities that developers can leverage.
At the time of reading it, I was tasked with writing unit tests in my job. It triggered my memory about Semantic Comparison with Likeness. The main idea of semantic comparison is to compare 2 objects with certain properties. It allows developers to define what equality means. The tuple supports the equality by default. So maybe I should be able to use the tuple to accomplish the same thing as Likeness.
In this post, I will write a simple unit test without Likeness or tuple, then refactors it with Likeness, finally uses Tuple. Let’s explore some code.
public class Product
{
public Guid Id { get; set;}
public string Name { get; set;}
public double Price { get; set;}
public string Description { get; set;}
}
[TestFixture]
public class ProductTests
{
[Test]
public void Test_Are_Products_Same()
{
var expectedProduct = new Product
{
Name = "C#",
Price = 10,
Description = "For the purpose of demoing test"
};
var reality = new Product
{
Name = "C#",
Price = 10,
Description = "For the purpose of demoing test"
};
// Assert that 2 products are the same. Id is ignored
}
}
The task is simple. How are we going to assert the 2 products?
Old Fashion
Very simple. We simply assert property by property.
[TestFixture]
public class ProductTests
{
[Test]
public void Test_Are_Products_Same()
{
var expectedProduct = new Product
{
Name = "C#",
Price = 10,
Description = "For the purpose of demoing test"
};
var reality = new Product
{
Name = "C#",
Price = 10,
Description = "For the purpose of demoing test"
};
Assert.AreEqual(expectedProduct.Name, reality.Name);
Assert.AreEqual(expectedProduct.Price, reality.Price);
Assert.AreEqual(expectedProduct.Description, reality.Description);
}
}
Some might think that we should override the Equals method in the Product class. I do not think it is a good idea. The definition of equality between production and unit test are tremendously different. Be careful before overriding equality.
The product class has 3 properties (except the Id property). So the code still looks readable. Think about the situation where there are 10 properties.
Likeness – Semantic Comparison
There is a blog post explaining it in the detail. In this demo, we can rewrite our simple test.
[TestFixture]
public class ProductTests
{
[Test]
public void Test_Are_Products_Same()
{
var expectedProduct = new Product
{
Name = "C#",
Price = 10,
Description = "For the purpose of demoing test"
}.AsSource()
.OfLikeness<Product>();
var reality = new Product
{
Name = "C#",
Price = 10,
Description = "For the purpose of demoing test"
};
Assert.AreEqual(expectedProduct, reality);
}
}
Likeness is a powerful tool in your testing toolbox. Check it out if you are interested in.
Tuple – Customized
The idea is that we can produce a tuple containing asserted properties and compare them. This allows us to flatten the structure if wished.
[TestFixture]
public class ProductTests
{
[Test]
public void Test_Are_Products_Same()
{
var expectedProduct = (Name = "C#", Price = 10, Description = "For the purpose of demoing test");
var reality = new Product
{
Name = "C#",
Price = 10,
Description = "For the purpose of demoing test"
};
Assert.AreEqual(expectedProduct, (reality.Name, reality.Price, reality.Description));
}
}
It might not look different from the Likeness approach. And I do not say which approach is better. It is just another way of doing things.
Summary
So which approach is better? None of them. Each has their own advantages and disadvantages. They are options in your toolbox. How they are used depends on you, developers. Definitely I will take advantages of the new Tuple in both production and unit test code.