Introduction
I want to demonstrate a nice time saving pattern for testing interfaces. It allows us to write the unit tests for an interface just once and use these tests to test any number of implementations of our interface.
The examples are written using MSTest in Visual Studio 2012.
Using the Code
String Searcher Interface
First, we need to define an interface for the example. Here is a simple interface to search strings. The example code contains a few different implementations of the string search algorithm. The implementations of these algorithms are from another CodeProject article by Carl Daniel.
public interface IStringSearcher
{
IEnumerable<int> SearchString(string stringToSearch, string pattern);
IEnumerable<int> SearchString(string stringToSearch, string pattern, int startingIndex);
}
Then, we have an abstract implementation of the interface StringSearcherBase which contains a few useful protected methods that our string search algorithms are going to need.
Finally, a few implementations of the algorithm. One that uses String.IndexOf, and another that uses the Bayer-Moore Algorithm + a few others.
public class StringSearcherIndexOf : StringSearcherBase
{
public override IEnumerable<int> SearchString
(string stringToSearch, string pattern, int startingIndex)
{
int patternLength = pattern.Length;
int index = startingIndex;
do
{
index = stringToSearch.IndexOf(pattern, index,
StringComparison.InvariantCultureIgnoreCase);
if (index < 0)
yield break;
yield return index;
index += patternLength;
}
while (true);
}
}
public class StringSearcherBoyerMoore : StringSearcherBase
{
public override IEnumerable<int> SearchString(string stringToSearch, string pattern,
int startingIndex)
{
int[] badCharacterShift = BuildBadCharacterShift(pattern);
int[] suffixes = FindSuffixes(pattern);
int[] goodSuffixShift = BuildGoodSuffixShift(pattern, suffixes);
int patternLength = pattern.Length;
int textLength = stringToSearch.Length;
int index = startingIndex;
while (index <= textLength - patternLength)
{
int unmatched;
for (unmatched = patternLength - 1;
unmatched >= 0 &&
(pattern[unmatched] == stringToSearch[unmatched + index]);
--unmatched)
;
if (unmatched < 0)
{
yield return index;
index += goodSuffixShift[0];
}
else
index += Math.Max(goodSuffixShift[unmatched],
badCharacterShift[stringToSearch[unmatched + index]] -
patternLength + 1 + unmatched);
}
}
}
Writing the Unit Tests
Having to write a set of tests for each implementation of the IStringSearcher interface would be a massive waste of time. What we want to do is write the tests once and reuse them to test all the implementations of the string search algorithm.
To do this, we are going to write an abstract base class where the tests will actually be written. Note the abstract method GetStringSearcherInstance.
[TestClass]
public abstract class StringSearcherTestBase
{
public abstract IStringSearcher GetStringSearcherInstance();
[TestMethod]
public void BasicTest()
{
IStringSearcher searcher = GetStringSearcherInstance();
List<int> indexes = searcher.SearchString(
"Hello. Welcome to unit testing interfaces",
"test").ToList();
Assert.AreEqual(1, indexes.Count);
Assert.AreEqual(23, indexes[0]);
}
[TestMethod]
public void NegativeTest()
{
IStringSearcher searcher = GetStringSearcherInstance();
var indexes = searcher.SearchString(
"Hello. Welcome to unit testing interfaces",
"uint").ToList();
Assert.AreEqual(0, indexes.Count);
}
Then, we simply implement this test class for each of the string algorithms we want to test and override the GetStringSearcherInstance method to return the IStringSearcher class we want to test.
[TestClass]
public class StringSearcherBoyerMoore_Tests : StringSearcherTestBase
{
public override IStringSearcher GetStringSearcherInstance()
{
return new StringSearcherBoyerMoore();
}
}
Looking in the test explorer, we see each test available for the implementation we are testing. It's as simple as that.

Moreover, if for some subtle reason, I want to make a test different in one of the implementations, then I can mark it as virtual in the test base class and override it.
For example, if the startingIndex is out of bounds, then all the string search classes just return no matches, but StringSearcherIndexOf throws an exception. So this test is overridden in StringSearcherIndexOf_Tests to test for the exception.
[TestClass]
public class StringSearcherIndexOf_Tests : StringSearcherTestBase
{
public override IStringSearcher GetStringSearcherInstance()
{
return new StringSearcherIndexOf();
}
[TestMethod]
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public override void NegativeTest_StartingIndexOutOfBounds()
{
IStringSearcher searcher = GetStringSearcherInstance();
var indexes = searcher.SearchString(
"Hello. Welcome to unit testing interfaces",
"unit",
500).ToList();
}
}
Points of Interest
The above was done using MSTest. I haven't tried with any other testing frameworks. It would be interesting to see how other unit test frameworks handle it.