Visse hurtigt gjorte ting
går der år og dag med:
dem man går i ring omkring
før man går i lag med.

-Piet Hein, Visse ting

Forskelligt fra mit liv...

Forskelligt fra mit liv...

Unittesting of interfaces PDF Udskriv

This post is a comment to a blog post by my former colleague Svein Arne about writing unit tests against interfaces. You should probably read that post first.

In that post he states:

The first thing we need to keep in mind is that we're writing the tests on something abstract. This means that we don't really know what to expect. When passing x in to the various implementations it's not certain that all of them will answer y. Actually hopefully only one of them would answer y where x is act and y is assert. If not there would be multiple implementations doing the exact same thing and that would kind of defeat the purpose.

This post is about why I doesn’t agree Smile

We should keep in mind that we are testing something abstract, but in my opinion we should only test things on the interface that is testable on that abstraction level. The purpose of an interface is to define some commonality between multiple implementations, and I think tests on interfaces should concentrate on that, and leave implementation specifics to be tested by tests written for the specific implementations.

On an appropriate abstraction level, all implementations of an interface should do the same – that’s why they implement the interface in the first place. And it is this "same" that we could benefit from validating through unittests for the interface

Lets look at the IComparable interface in .Net as an example. All classes implementing this interface, should abide to some common rules like this:

Let x and y be comparables then: if x < y then y > x and if x = y then y = x

So, we could write a test for the IComparable interface:

public void TestSanityOfCompareTo<T>(T obj1, T obj2) where T : IComparable<T>
{
    int compare = obj1.CompareTo(obj2);
    if (compare < 0)
    {
	Assert.IsTrue(obj2.CompareTo(obj1) > 0);
    }
    else if (compare == 0)
    {
	Assert.IsTrue(obj2.CompareTo(obj1) == 0);
    }
    else //compare > 0
    {
	Assert.IsTrue(obj2.CompareTo(obj1) < 0);
    }
}

All implementations of IComparable should pass this test!

Each implementation should also have its own tests, for example a String : IComparable class should be tested to ensure that “a” < “b” and maybe “A” = “a” (if it should be case insensitive). We could of course write helper-methods to perform this kind of tests through the interface, but that’s not really interesting in the context of tests for interfaces.

I’m usually trying to think of unit tests as descriptions of how code should behave. So a unit test for an interface, should be a description of how implementations of that interface should behave.

What Svein Arne is doing in his blog post, is merely constructing a framework for testing the implementations – and that can be usable in it’s own right, but to take his calculator example, I’d rather see two tests like:

[TestMethod]
public void OctalMultiply()
{
    OctalCalculator calc = new OctalCalculator();
    Assert.AreEqual(61, calc.Multiply(7, 7));
}

[TestMethod]
public void DecimalMultiply()
{
    DecimalCalculator calc = new DecimalCalculator();
    Assert.AreEqual(49, calc.Multiply(7, 7));
}

Instead of the “unified test” presented on Svein Arnes blog. Simply because the above is simpler, and can be divided into one test class per implementation, and when we get to dependencies etc. we won’t complicate things unnecessarily.

So, my point is: Unit tests for interfaces is a splendid idea, as long as they are written to ensure that all implementations adhere to some common rules defined in terms of the interface and it’s methods. As soon as it’s something implementation specific we want to test – for example if different implementations should return different results, you could just as well write the tests against the implementations – it will be simpler and easier to understand.

I can come up with another couple of examples of interfaces you could/should write tests for – that is: Tests that must pass for all implementations:

Imagine a IStringPersister interface – saving and retrieving string data based on a key. All implementations must be able to save a string and retrieve it later on. It could be implemented on top of an xml-file, a SQL database or even a Hash table. Here you should write tests saving some strings and retreiving them again, asserting that the saved and the retreived strings are the same.

You could also imagine an ISortable interface:

public interface ISortable<T> : IList<T> where T : IComparable<T>
{
    void Sort();
}

A test for such an interface could look like this:

public void TestSort<T>(ISortable<T> sortable) where T : IComparable<T>
{
    if (sortable.Count > 1)
    {
        sortable.Sort();
        for (int i = 0; i < sortable.Count - 1; i++)
        {
            Assert.IsTrue(sortable[i].CompareTo(sortable[i + 1]) <= 0, "Item " + i + " is greater than item " + (i+1));
        }
    }
}

Again this is testing functionality that should behave the same for all implementations, no matter what kind of list and which sort algorithm is being used.

 
Antal kommentarer til denne artikel (2)
http://www.dissertationswriting.info/
2 Onsdag, 02 Maj 2012 13:01
Dissertation Help UK
Such a good one.Thanks for sharing.
You are 100% right!
1 Mandag, 25 Oktober 2010 09:22
Svein Arne Ackenhausen
It's funny that you should write this exact reply. After writing the previous blog post I had a talk with Greg. This is what he told me: "Dude, you're doing it wrong". And then after some fiddling he had Grensesnitt ready (http://github.com/gregoryyoung/grensesnitt). With grensesnitt you write tests like you mention only considering the abstraction. It will then go on to building the test at runtime for all classes implementing or inheriting from the abstract class. Only works with nunit though. But it is a neat little tool.
Glad to see you're getting your voice out there!
 
Joomla 1.5 Templates by Joomlashack