单元测试类继承关系应聚焦行为契约:验证子类实例能否正确调用、重写父类方法,构造函数是否正确初始化属性并执行super(),以及instanceof和原型链是否符合预期。

对类继承关系编写单元测试,核心是验证子类是否正确继承了父类的属性、方法,是否能正确覆盖或扩展父类行为,以及构造函数逻辑是否符合预期。不需要单独测试“继承语法”,而是围绕行为和契约来设计用例。
测试父类公共方法在子类实例上是否可用
确保子类实例能直接调用父类定义的非私有方法(ES6 中无真正私有方法,暂指非 # 开头的普通方法)。重点不是“能否调用”,而是“调用结果是否符合父类契约”。
- 创建子类实例,调用继承来的方法,断言返回值、副作用(如修改实例状态)与父类文档或实现一致
- 若父类方法依赖 this 上的属性,需确认子类构造后这些属性已正确初始化(包括通过 super() 传递参数)
- 例如:Animal 有 makeSound() 返回 "sound",Dog 继承它未重写,则 new Dog().makeSound() 应仍返回 "sound"
测试子类对父类方法的重写(override)是否生效且合理
当子类用同名方法重新定义行为时,测试应聚焦于“新行为是否达成设计意图”,而非仅仅“是否没调用父类原版”。
- 调用被重写的方法,验证输出、内部状态变化、抛出错误等是否符合子类语义(如 Dog.bark() 可能返回 "woof",而不再是通用 "sound")
- 若子类方法中显式调用了 super.methodName(),可结合 jest.spyOn 检查父类方法是否被调用一次、参数是否正确
- 避免断言“不能访问父类原始方法”——JS 中仍可通过 Object.getPrototypeOf(Child.prototype).methodName.call(instance) 访问,这不是测试重点
测试构造函数逻辑与属性初始化是否正确串联
继承链中各层 constructor 的执行顺序和参数传递极易出错,这是继承相关 bug 的高发区。
- 检查子类实例是否拥有父类期望的实例属性(如 this.name、this.age),且值由传入参数或默认值正确设定
- 若父类构造函数有副作用(如事件绑定、资源初始化),需模拟环境并验证其是否发生(例如用 jest.fn() 替换依赖,检查是否被调用)
- 显式测试 super() 调用缺失或位置错误的情形——这通常导致运行时报错,可在测试中用 expect(() => new BadChild()).toThrow() 捕获
测试 instanceof 和原型链是否符合预期
虽然不是业务行为,但它是继承关系的底层体现,适合做快速契约校验,尤其在复杂多层继承或混入(mixin)场景中。
- 使用 expect(instance instanceof ChildClass).toBe(true) 和 expect(instance instanceof ParentClass).toBe(true) 确认类型归属
- 必要时检查 Object.getPrototypeOf(instance) === ChildClass.prototype,以及 Object.getPrototypeOf(ChildClass.prototype) === ParentClass.prototype
- 注意:不要用 instance.constructor === ChildClass 断言,因为 constructor 属性可被意外修改;优先依赖 instanceof











