Oct 7, 2008

Test Requirements First

Today I found a post about The Compare Contract by BCL Team. In brief, one of the customers complained about the breaking changes made in SP1 compared to RTM version. Actually, the ComparedTo method of the StringWrapper class was changed which affected sorting behavior.

It appeared that ComparedTo method was implemented incorrectly. Therefore, it was decided to change it. MSDN describes several requirements that must be met by a particular implementation of IComparable<T> interface.

I see this as a big bonus for any developer implementing IComparable<T> interface. Even before starting to implement the method you can write very strict Unit Tests that will help you to implement a method that will satisfy common requirements for any sorting algorithm.

As you see, you can end up with 5 unit test. If you will use MbUnit, for example, you can employ Row Tests to specify more precise requirements for your interface implementation very easy.

For example I ended up with 15 tests. It took me about 15 minutes. Here they are:

namespace CompareToContract.UnitTests
{
using MbUnit.Framework;

[TestFixture]
public class StringWrapperTests
{
[RowTest]
[Row("")]
[Row("value")]
[Row(null)]
public void CompareTo_SameValue_ShouldReturnZero(string value)
{
StringWrapper wrapper = new StringWrapper() { Value = value };
Assert.AreEqual(wrapper.CompareTo(wrapper), 0, "A.CompareTo(A) should return 0.");
}

[RowTest]
[Row("", "")]
[Row("value", "value")]
[Row(null, null)]
public void CompareTo_AnotherEqualValue_ShouldReturnZero(string value1, string value2)
{
StringWrapper a = new StringWrapper() { Value = value1 };
StringWrapper b = new StringWrapper() { Value = value2 };

Assert.AreEqual(a.CompareTo(b), 0, "A'value'.ComparedTo(b'value') should return 0.");
}

[RowTest]
[Row("", "", "")]
[Row("value", "value", "value")]
[Row(null, null, null)]
public void CompareTo_AandBandCequal_ShouldReturnZero(string value1, string value2, string value3)
{
StringWrapper a = new StringWrapper() { Value = value1 };
StringWrapper b = new StringWrapper() { Value = value2 };
StringWrapper c = new StringWrapper() { Value = value3 };

Assert.AreEqual(a.CompareTo(b), 0, "A'value'.ComparedTo(B'value') should return 0.");
Assert.AreEqual(b.CompareTo(c), 0, "B'value'.ComparedTo(C'value') should return 0.");
Assert.AreEqual(a.CompareTo(c), 0, "A'value'.ComparedTo(C'value') should return 0.");
}

[RowTest]
[Row("1", "2")]
[Row("value1", "value2")]
[Row(null, "1")]
public void CompareTo_IfAComparedToBReturnValueThenBComparedToA_ShouldReturnSameValueButDifferentInSign(string value1, string value2)
{
StringWrapper a = new StringWrapper() { Value = value1 };
StringWrapper b = new StringWrapper() { Value = value2 };

Assert.AreEqual(a.CompareTo(b), -1 * b.CompareTo(a), "a.ComparedTo(b) should equal to -1 * b.ComparedTo(a).");
}

[RowTest]
[Row("1", "2", "3")]
[Row("value3", "value2", "value1")]
[Row("value1", "value2", "value3")]
public void CompareTo_IfAComparedToBReturnsValueWithTheSameSignAsBComparedToCThenACompareToC_ShouldReturnValueWithTheSameSign(string value1, string value2, string value3)
{
StringWrapper a = new StringWrapper() { Value = value1 };
StringWrapper b = new StringWrapper() { Value = value2 };
StringWrapper c = new StringWrapper() { Value = value3 };

int abResult = a.CompareTo(b);
int bcResult = b.CompareTo(c);
int acResult = a.CompareTo(c);

Assert.IsTrue(Math.Sign(abResult) == Math.Sign(bcResult), "A.ComparedTo(B) should have the same sign as B.ComparedTo(C).");
Assert.IsTrue(Math.Sign(abResult) == Math.Sign(acResult), "A.ComparedTo(C) should have the same sign as A.ComparedTo(B).");
}
}
}



The old implementation of CompareTo completed with 10 succeeded and 5 failed tests. While implementation provided by BCL Team completed with all 15 succeeded. This way I can trust this implementation of CompareTo method.



Conclusion



Test your requirements before you right the code. This will minimize your time and efforts to understand (remember all the time) requirements of implementation and will help you to write the code you need, not the code you can write.



Hope this helps!



Technorati Tags: ,,

No comments: