Reputation: 1281
I have a set of base tests that are used to test multiple implementations of a interface. The way I modelelled this was by creating a base text fixture with a [Ignore] attribute.
[TestFixture]
[Ignore]
public class BaseTests
{
// Use your imagination for the actual name
public virtual ITestableThing GetConcrete()
{
return null;
}
// All of my unit tests here
}
And then I write a subclass for each interface implementation:
public class ConcreteThingTests : BaseTests
{
public override ITestableThing GetConcrete()
{
return new ConcreteThing();
}
}
This works well, as I have all of the tests for ALL implementations in one place, and the sub classes just specify the implementation.
The problem is that I have to put the [Ignore] attribute on the base class, or NUnit will try to run the tests (and fail).
Because of this, my test results are always cluttered up with a set of Ignored tests, and while it's not a big deal, I thought there might be a better pattern for this that avoids having to ignore tests.
So, am I implementing test fixture inheritance wrong?
Upvotes: 9
Views: 7644
Reputation: 144176
The NUnit test runner appears to ignore the base class if it is marked abstract:
public abstract class BaseTests
{
}
Upvotes: 19
Reputation: 1991
You would normally set the test attributes on your concrete test classes, not the base class.
Since you seem to test the same functionality for multiple classes, you could skip the whole test hierarchy and inject the concrete classes to be tested to that test-baseclass.
To do that with NUnit you could use the TestCaseSource attribute with a class factory method as a parameter. An example of that can be found here: How to pass dynamic objects into an NUnit TestCase function?
Making up some code for your particular case, it could be like shown below:
/// <summary>
/// Earlier known as your BaseTests class
/// </summary>
[TestFixture]
public class TestOfConcreteImplementationsOfInterface
{
[TestCaseSource("CreateConcretes")]
[Test]
public void VerifyImplementations(IWhatever thing)
{
int input = 42;
int result = thing.DoSomething(input);
Assert.That(result, Is.EqualTo(input));
}
/// <summary>
/// Factory method for the concrete classes. If you want this in a seperate class, you can do that too using the
/// ctor public TestCaseSourceAttribute(Type sourceType, string sourceName);
/// </summary>
public IEnumerable<IWhatever> CreateConcretes
{
get
{
yield return new A();
yield return new B();
}
}
}
public interface IWhatever
{
int DoSomething(int x);
}
public class A : IWhatever
{
public int DoSomething(int x)
{
return x;
}
}
public class B : IWhatever
{
public int DoSomething(int x)
{
return x;
}
}
Upvotes: 5