我有一个案例,我的基类'构造函数在提供无效参数时抛出异常 由于我不想一遍又一遍地复制/粘贴相同的测试,我想确保被测系统实际上实现了IFoo,IBar和MyBaseClass。 一方面,我的类将实现IFoo,IBar和MyBaseClass是有道理的,但另一方面,如果我的实现发生了变化,我将再进行一次维护测试,如果我要做出一个约定,那么可能会有一些开销重新安排继承层次结构时。
答案 0 :(得分:2)
作为一项规则,我更喜欢测试行为,而不是实现。 例如,我会确保我的SUT可以做 IFoo和IBar提供的内容。从业务角度来看,MyClass是否实现IFoo并不重要。 重要的是objectUnderTest实现DoThis()。
阿萨弗。
答案 1 :(得分:1)
我认为您可以通过使用包含一些测试的抽象基类来解决这个问题,并使用抽象方法来获取特定的实现。
在每个具体的实现测试类中仍然需要一些代码,但是应该确保如果你从基类改变实现,你的构造函数仍然会被测试。
我刚刚做了类似的事情来测试一个方法,对于许多实现来说这是一个无操作(它只返回它给出的内容),但对于某些实现它做了一些事情,所以没有操作代码测试是在一个单个基类,带有一个抽象方法来获取要测试的对象(获取无操作方法所在的接口的实例),以及应该只是一个无操作的具体实现扩展该类并覆盖抽象方法以返回我们想要测试方法的类的实例。
这帮助我解决了我的问题,希望它也能帮到你。
public abstract class BaseClass
{
public abstract void CallConstructor(SomeType arg1, SomeType2 arg2);
[Test]
public void Constructor_WhenArg1IsNull_ArgumentNullExceptionIsThrown()
{
Assert.Throws<ArgumentNullException>(()=>CallConstructor(null, new SomeType2()));
}
[Test]
public void Constructor_WhenArg2IsNull_ArgumentNullExceptionIsThrown()
{
Assert.Throws<ArgumentNullException>(()=>CallConstructor(new SomeType(), null));
}
}
[TestFixture]
public class ConcreteImplementation1Tests : BaseClass
{
public override void CallConstructor(SomeType arg1, SomeType2 arg2)
{
new ConcreteImplementation1(arg1,arg2);
}
}
[TestFixture]
public class ConcreteImplementation2Tests : BaseClass
{
public override void CallConstructor(SomeType arg1, SomeType2 arg2)
{
new ConcreteImplementation2(arg1,arg2);
}
}
除此之外,相同的技术可用于测试常见的
实现接口的所有类的功能。以IList为例:
public abstract class ListImplementationsCommonTests
{
public abstract IList GetListImplementation();
[Test]
public void Add_WhenValidItemIsAdded_ItCanBeFound()
{
IList list = GetListImplementation();
object item = new Object();
list.Add(item);
Assert.That(list.Contains(item));
}
[Test]
public void Add_WhenNullIsAdded_ArgumentNullExceptionIsThrown()
{
IList list = GetListImplementation();
Assert.Throws<ArgumentNullException>(()=>list.Add(null));
}
...
//more common tests
...
}
然后可以使用相同的代码测试IList的每个实现(so ArrayList,LinkedList,DoubleLinkedList,SortedList等),而无需一次又一次地重复相同的测试:
[TestFixture]
public class ArrayListTests: ListImplementationCommonTests
{
public override IList GetListImplementation()
{
return new ArrayList();
}
...
//Extra specific tests for the ArrayList
}
[TestFixture]
public class LinkedListTests: ListImplementationCommonTests
{
public override IList GetListImplementation()
{
return new LinkedList();
}
...
//Extra specific tests for the LinkedList
}
[TestFixture]
public class SortedListTests: ListImplementationCommonTests
{
public override IList GetListImplementation()
{
return new SortedList();
}
...
//Extra specific tests for the SortedList
}
答案 2 :(得分:-1)
测试IFoo和IBar的实现,与实现它们的Class分开。因此,在测试实现类时,您不必测试它。
对于MyBaseClass(如果它被声明为MustInherit),我将创建一个测试模拟(继承自MyBaseClass并位于测试项目中)并测试MyBaseClass中的所有操作。