单元测试从抽象类B派生的类a

本文关键字:派生 抽象类 单元测试 | 更新日期: 2023-09-27 17:54:07

我需要对派生自抽象类a的类B进行单元测试,该类a有一些实现。

我的问题是:您应该单元测试父类型(例如抽象ClassB)或子类/派生类型(例如ClassA)

单元测试从抽象类B派生的类a

编写单元测试部分是为了维护代码的完整性。为了与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());
    }
}

为了重复,您通常不会编写特定于基类的测试,因为实现细节通常在派生类型中。

<标题>额外阅读
  • 设计原则和设计模式
  • 如何对私有方法进行单元测试?
  • 单元测试值得努力吗?
  • 单元测试命名最佳实践

一般来说,您应该只通过对象的公共API进行测试。在这种情况下,这意味着测试具体的子类本身,抽象的超类是一个实现细节。

如果您觉得这会导致不必要的重复,并且/或者您正在开发某种框架并提供抽象基类(或者更一般的接口)作为扩展点,那么您可以研究契约测试的概念。契约测试的总结:针对公共API(接口或抽象基类)编写测试,描述该接口的所有实现应该保留的所有不变量。然后在这个接口的具体实现上运行这些测试。

如果抽象类/接口是公开暴露的API,我只推荐契约测试。"如果我单独测试每个具体实现,我就复制了很多测试"的味道可以用更好的方式缓解,例如用对象组合代替继承关系。