如果调用 super() 则开玩笑的单元测试

Posted

技术标签:

【中文标题】如果调用 super() 则开玩笑的单元测试【英文标题】:Jest unit-testing if super() is called 【发布时间】:2018-12-15 09:31:33 【问题描述】:

我有一个自定义错误类,它扩展了 javascript 中的内置错误类。我想出的问题是“super()”方法没有通过我的 Jest 单元测试来检查它是否被调用。

export class AppError extends Error 
  public name: string;
  public message: string;
  public status?: number;
  public data?: any;
  constructor(message: string, status?: number, data?: any) 
    super(); <-- this guy!!
    this.name = 'AppError';
    this.status = status || 500;
    this.message = message;
    this.data = data;
  

有什么方法可以测试吗?谢谢。

【问题讨论】:

你用什么来单元测试你的代码?一个想法是使用 Jasmine 中的“间谍”(我通常使用 Karma+Jasmine 进行单元测试)。 @RoboBear 我正在使用 Jest。 看起来spy可以用在super.methodA()等方法上。它不能监视自己的 super() 方法。 通常最好测试影响本身,而不是说“X 被调用”。 @loganfsmyth 实际上,最好同时测试两者,额外的断言使测试更强大,故障排除更容易。但是在这种情况下,由于类的工作方式,测试是否调用了 super() 是多余的。 【参考方案1】:

没有理由去检查 super() 是否在原生 ES6 类和用 Babel 转译的类中都没有被调用。

在子类构造函数中不调用super会导致类实例化出错:

ReferenceError: 在访问 'this' 或从派生构造函数返回之前,必须在派生类中调用超级构造函数

Babel provides a safeguard 也是如此:

function _possibleConstructorReturn(self, call)  if (!self)  throw new ReferenceError("this hasn't been initialised - super() hasn't been called");  return call && (typeof call === "object" || typeof call === "function") ? call : self; 

可以通过模拟子类原型来检查是否调用了父构造函数(对断言super() 参数很有用),例如:

let ParentOriginal;
let ParentMock;

beforeEach(() => 
  ParentOriginal = Object.getPrototypeOf(AppError);
  ParentMock = jest.fn();
  Object.setPrototypeOf(AppError, ParentMock);
);

it('..', () => 
  new AppError(...);
  expect(ParentMock.mock.calls.length).toBe(1);
)

afterEach(() => 
  Object.setPrototypeOf(AppError, ParentOriginal);
);

它应该在原生类和使用 Babel 转译的类中模拟 super

但是这个测试是多余的,因为缺少super() 无论如何都会导致错误。测试AppError 继承自Error 是这里需要测试的所有内容:

expect(new AppError(...)).toBeInstanceOf(Error)

【讨论】:

我遇到的问题是我用 jest 检查了单元测试覆盖率,而 jest 说我没有覆盖 super() 行。那么这是开玩笑的错误吗? 我会说这是一个错误,并建议就此提出问题。 我知道这是一年后的事了....这种方法只适用于 Babel 吗?我试过了,但我的超级构造函数仍然被调用而不是模拟。我已经在基类上测试了功能,只需要断言正确的参数被传递给 super @hvgotcodes 正如答案所说,这也应该适用于本机类。答案模拟了一个原型,因为父类是 Error 内置的。如果是自定义类且类在不同的模块中,可以mock parent的模块。 @estus,你有这方面的例子吗?谢谢!

以上是关于如果调用 super() 则开玩笑的单元测试的主要内容,如果未能解决你的问题,请参考以下文章

开玩笑单元测试返回“MongoError:拓扑被破坏”

使用玩笑的反应单元测试失败

单元测试基本框架和8个测试方面

单元测试基本框架和8个测试方面

单元测试集成测试

createWriteStream 的 ('error') 上的开玩笑单元测试