在规范`expect`中复制Node.js`assert`断言

时间:2016-06-02 22:21:51

标签: javascript node.js unit-testing assert

与使用自定义开发人员友好检查的非断言代码相反,

class Some {
  constructor(arg) {
    if (Array.isArray(arg) && arg[0] === 'foo')
      this.foobar = arg.concat('bar').join('');
    else
      console.error('Bad Some constructor arg');
  }
}

目前经过测试的代码充满了节点assert断言以及具有相当有意义的message参数:

class Some {
  constructor(arg) {
    assert.deepEqual(arg, ['foo'], 'Some constructor arg');
    this.foobar = arg.concat('bar').join('');
  }
}

断言就在那里

  • 保持代码平整且可读
  • 提供有关使用调用堆栈的错误使用情况的有意义的反馈
  • 阻止功能执行并且不会进一步传播错误
  • 抛出错误并将错误处理留给调用者

目前的规格可能如下:

it('...', () => {
  let some = new Some(['foo']);
  expect(some).to...

并且它将通过 - 在测试代码中声明的特定用法是不合需要的用法。

要部分重叠代码断言,它甚至可能是

it('...', () => {
  const { AssertionError } = require('assert');
  let some = new Some(['foo']);
  expect(some).to...
  expect(() => new Some(['bar']).to.throw(AssertionError);

因此,我们基本上假设已经使用assert在代码本身中完成了一半的测试工作,并跳过详细信息(to.not.throw并匹配AssertionError消息)。

上面的例子使用了Mocha + Chai,但同样的事情适用于Jasmine。

  • 应将app断言视为任何其他代码行,并使用spec断言加倍(抛出不抛出AssertionError消息匹配),采取捷径有什么后果?

  • 除了assert之外,测试覆盖率工具(伊斯坦布尔)是否可以考虑应用代码中的expect断言?

  • 可能会让测试跑步者感到困惑的是它是应用程序,而不是出现错误的规范断言?

成功的开源JS项目的一些例子证明或反驳断言断言'实践中的观点也可能有所帮助。

3 个答案:

答案 0 :(得分:1)

  

应该将app断言视为任何其他代码行,并使用spec断言加倍(抛出,不抛出,AssertionError消息匹配),获取快捷方式的后果是什么?

应用程序断言是为了通知开发人员不正确使用某段代码,理想情况是它们永远不会在生产中发生。如果确实发生了这种情况,那么它们就像标准错误一样,可以用来识别出现问题的难度。但理想情况下,它们是开发过程中的第一道防线,它们应该只在那时发生。 (因此,这就是为什么在某些语言中你可以一起禁用运行时断言的一个原因)

如果你编写了一些使用断言的类来确保输入参数被验证或者程序没有被不一致地使用,那么确定将该逻辑放在单元测试中是很有意义的。如果您要在某个时候更改断言,您希望能够测试您是否打破了其他人的代码。

  

测试覆盖率工具(伊斯坦布尔)是否可以考虑应用程序代码中的断言断言?

是。如果您设置了一个单元测试,它将触发一个断言,然后在chai中捕获它,那么该代码路径将显示在您的覆盖率报告中。这与任何其他代码路径没有什么不同,除非我误解你的问题。

  

可能会让测试跑步者感到困惑的是它是应用程序,而不是出现错误的规范断言?

使用assert模块编写断言时,它会抛出AssertionError。这是AssertionError模块中的assert类。 当chai抛出错误时它也会抛出一个AssertionError,但这将是一个完全不同的来自chai模块的类,它们只共享名称。 因此,关于断言的起源,不应该有任何混淆 通常,您不会在所有通过try / catch构造的测试代码中捕获断言,因此这不应该是一个问题。

通常断言测试的复杂状态要少于单元测试。但是断言结束和单元测试应该开始的地方确实没有正式定义。 更多阅读:

https://softwareengineering.stackexchange.com/questions/18288/are-asserts-or-unit-tests-more-important

答案 1 :(得分:1)

  

应该将app断言视为任何其他代码行,并使用spec断言加倍(抛出,不抛出,AssertionError消息匹配),获取快捷方式的后果是什么?

我不建议这样做。这就像测试测试一样:虽然技术上可行,但通常你不这样做,因为它不值得花费。

  

测试覆盖率工具(伊斯坦布尔)是否可以考虑应用程序代码中的断言断言?

您想要获得什么样的行为?通过单元测试,可以非常清楚地了解什么:运行测试并监视访问哪些代码。但是你想用assert做什么(在代码中)?如果某个单元测试达到了assert语句,那么代码显然是测试覆盖的。如果不是 - 围绕断言语句的某些代码是否算作测试所涵盖的?您想要计算多少代码?这一切都变得非常讨厌,我不相信存在一些适当的解决方案。

此外,整个测试覆盖的指标至少是臭的 - 只有存在测试才能达到一些代码的事实告诉你它的正确性如此之少!

  

可能会让测试跑步者感到困惑的是它是应用程序,而不是出现错误的规范断言?

这是(IMO正确)威廉回答的。或者有什么遗漏? :)

答案 2 :(得分:0)

我通常建议我采用两种方法来解决这个问题:

  1. 在单元测试中进行测试(我知道它与运行时断言不同,但你可以测试你的稳健性在单元测试中有效)

  2. 构建代码,以便首先出现退出条件并return。然后,您可以使用平坦(无缩进)空间来编写验证后代码。如果您愿意,可以编写自己的记录器/处理程序或“调用者中间件”来中断执行致命错误。