我需要对从抽象类A派生的类B进行单元测试,该抽象类有一些实现。
我的问题是:你应该单元测试父类型(例如抽象ClassB
)还是子类/派生类型(例如ClassA
)
答案 0 :(得分:0)
通常,您应该只测试对象的公共API。在这种情况下,这意味着测试具体的子类本身,抽象的超类是一个实现细节。
如果您认为这会导致不必要的重复和/或您正在开发某种框架并提供抽象基类(或更一般的接口)作为扩展点,您可能会研究contract tests的概念。合同测试摘要:针对公共API(接口或抽象基类)编写测试,描述应该为此接口的所有实现保留的所有不变量。然后在此接口的具体实现上运行这些测试。
如果抽象类/接口是公开公开的API,我只会建议合同测试。如果我单独测试每个具体的实现,我会复制大量的测试,并且可以更好的方式减轻因素,例如:通过用对象组合替换继承关系。
答案 1 :(得分:0)
部分测试的编写部分是为了维护代码的完整性。为了与 Pareto原则(80/20规则)保持一致,您要测试的实现细节通常是派生类型。所以...
单元测试应写为 派生类型/子类,但单元测试实现应根据SOLID Liskov替换引用父类型原理:
“程序中的对象应该可以替换为其子类型的实例,而不会改变该程序的正确性"
换句话说,您正在测试Dog
,但单元测试源代码将引用Mammal
:
Mammal pet = new Dog();
pet.Speak();
如果基类型(例如Mammal
)包含您要进行单元测试的可执行代码,则必须创建派生类型的实例(例如Dog
)。例如,你可以这样做:
[TestCase]
public class MammalTest
{
[TestMethod]
AbstractMethodNameHere_YourTestCase_YourExpectedResults()
{
Mammal pet = new Dog();
// Here you could test the method that has been implemented
// in the base class.
Assert.IsTrue(pet.AbstractMethodNameHere());
}
}
要重新迭代,通常不会编写特定于基类的测试,因为实现细节通常在派生类型中。