I am writing a series of collection classes in C#, each of which implement similar custom interfaces. Is it possible to write a single collection of unit tests for an interface, and automatically run them all on several different implementations? I would like to avoid any duplicated testing code for each implementation.
I'm willing to look into any framework (NUnit, etc.) or Visual Studio extension to accomplish this.
For those looking to do the same, I posted my concrete solution, based off of avandeursen's accepted solution, as an answer.
Expanding on Joe's answer, you can use the [TestCaseSource] attribute in NUnit in a similar way to MBUnit's RowTest. You could create a test case source with your class names in there. You could then decorate every test which the TestCaseSource attribute. Then using Activator.CreateInstance you could cast to the interface and you'd be set.
Something like this (note - head compiled)
You can use the [RowTest] attributes in MBUnit to do this. The example below shows where you pass the method a string to indicate which interface implementation class you want to instantiate, and then creates this class via reflection:
In the [Row] attributes, you can pass any arbitrary number of input parameters, such as input values for testing or expected values to be returned by method invocations. You will need to add arguments of the corresponding types as test method input arguments.
This is my concrete implementation based off of avandeursen's answer:
Each interface implementation then defines the following test class:
SomeTest
is run once for each concreteTestClass
derived fromIMyInterfaceTests
. By using an abstract base class, I avoid the need for any mock implementations. Be sure to addTestClassAttribute
to both classes or this won't work. Lastly, you can add any implementation-specific tests (such as constructors) to the child class if desired.Yes, that is possible. The trick is to let your unit class test hierarchy follow the class hierarchy of your code.
Let's assume you have an interface
Itf
with implementing classesC1
andC2
.You first create a test class for
Itf
(ItfTest
). To actually exercise the test, you need to create a mock implementation of yourItf
interface.All tests in this
ItfTest
should pass on any implementation ofItf
(!). If not, your implementation does not conform to the Liskov Substitution Principle (the "L" in Martin's SOLID principles of OO design)Thus, to create a test case for
C1
, yourC1Test
class can extendItfTest
. Your extension should replace the mock object creation with the creation of aC1
object (injecting it in, or using a GoF factory method). In this way, allItfTest
cases are applied to instances of typeC1
. Furthermore, yourC1Test
class can contain additional test cases specific toC1
.Likewise for
C2
. And you can repeat the trick for deeper nested classes and interfaces.References: Binder's Polymorphic Server Test pattern, and McGregor's PACT -- Parallel Architecture for Component Testing.