我有一组基本测试,用于测试接口的多个实现。我对其进行模拟的方法是创建一个带有[Ignore]属性的基础文本夹具。
[TestFixture]
[Ignore]
public class BaseTests
{
// Use your imagination for the actual name
public virtual ITestableThing GetConcrete()
{
return null;
}
// All of my unit tests here
}
然后我为每个接口实现编写一个子类:
public class ConcreteThingTests : BaseTests
{
public override ITestableThing GetConcrete()
{
return new ConcreteThing();
}
}
这很有效,因为我在一个地方完成了所有实现的所有测试,子类只是指定了实现。
问题是我必须将[Ignore]属性放在基类上,否则NUnit会尝试运行测试(并失败)。
正因为如此,我的测试结果总是被一组忽略测试混乱,虽然这不是什么大问题,但我认为可能有一个更好的模式,以避免不得不忽略测试。
那么,我实现测试夹具继承是错误的吗?
答案 0 :(得分:15)
如果基类被标记为抽象,则NUnit测试运行器似乎忽略它:
public abstract class BaseTests
{
}
答案 1 :(得分:4)
您通常会在具体测试类上设置测试属性,而不是基类。
由于您似乎为多个类测试了相同的功能,因此您可以跳过整个测试层次结构并将要测试的具体类注入该测试基类。
要使用NUnit执行此操作,您可以将TestCaseSource属性与类工厂方法一起用作参数。可以在此处找到一个示例:How to pass dynamic objects into an NUnit TestCase function?
为您的特定情况编写一些代码,它可能如下所示:
/// <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;
}
}