【问题标题】:Test for expected failure in Mocha测试 Mocha 中的预期失败
【发布时间】:2013-01-30 12:17:11
【问题描述】:

使用 Mocha,我试图测试构造函数是否抛出错误。我无法使用 expect 语法做到这一点,所以我想做以下事情:

it('should throw exception when instantiated', function() {
  try {
    new ErrorThrowingObject();
    // Force the test to fail since error wasn't thrown
  }
  catch (error) {
   // Constructor threw Error, so test succeeded.
  }
}

这可能吗?

【问题讨论】:

  • “强制摩卡测试失败”听起来像你想要expect(false).to.be.true,但实际上讨论的是测试预期失败,我已经请求相应地编辑标题。

标签: node.js unit-testing mocha.js


【解决方案1】:

您可以尝试使用Chai's throw 构造。例如:

expect(Constructor).to.throw(Error);

【讨论】:

  • 为什么你不能只做一个 return false ;让 mocha 测试失败?
  • 使用 done() 传递一个错误实例,如下所示:done(new Error()),没有“done()”回调,你只是抛出一个错误,而不是返回一个错误跨度>
【解决方案2】:

如果您使用的是should.js,您可以使用(new ErrorThrowingObject).should.throw('Option Error Text or Regular Expression here')

如果你不想单独的库,你也可以这样做:

it('should do whatever', function(done) {
    try {
        ...
    } catch(error) {
        done();
    }
}

这样,您就知道如果测试完成,错误就会被捕获。否则,您将收到超时错误。

【讨论】:

  • (new ErrorThrowingObject).should.throw('Option Error Text or Regular Expression here') 不起作用,new 需要像这样包裹在匿名函数中: (function() {new ErrorThrowingObject}).should.throw('Option Error Text or Regular Expression here')
  • 或者你可以这样做 ErrorThrowingObject.should.throw('Option Error Text or Regular Expression here')
【解决方案3】:

应该.js

通过 should.fail

使用 should.js
var should = require('should')
it('should fail', function(done) {
  try {
      new ErrorThrowingObject();
      // Force the test to fail since error wasn't thrown
       should.fail('no error was thrown when it should have been')
  }
  catch (error) {
   // Constructor threw Error, so test succeeded.
   done();
  }
});

您可以使用应该throwError的替代方法

(function(){
  throw new Error('failed to baz');
}).should.throwError(/^fail.*/)

使用 throw api 使用 chai

var expect = require('chai').expect
it('should fail', function(done) {
  function throwsWithNoArgs() {
     var args {} // optional arguments here
     new ErrorThrowingObject(args)
  }
  expect(throwsWithNoArgs).to.throw
  done()
});

【讨论】:

  • 如果 throwsWithNoArgs 本身不返回错误,而只是在接收到错误的参数时怎么办?我想用不同的参数进行测试?像: expect(throwsWithNoArguments.call(null, x1, x2)).to.throw(Error) 将是一个选项?
  • expect(throw) 总是调用不带参数的 throws 函数。在您的情况下,您可以更改 throwsWithNoArgs 主体以使用不正确的参数调用另一个函数。或者,您可以使用绑定expect(throwsWithIncorrectArgs.bind(null, x1, x2)).to.throw(Error)
【解决方案4】:

柴现在有

should.fail()expect.fail()

https://github.com/chaijs/chai/releases/tag/2.1.0

【讨论】:

  • 嗯……我想是不是? ...如果您愿意,您可以将“to”插入链中,这样更符合语法,这就是提供小词的原因(“以下内容作为可链接的 getter 提供,以提高断言的可读性。他们除非它们已被插件覆盖,否则不提供测试功能。")
  • expect.failexpect 的唯一静态方法,如您所见here。没有静态可链接的 getter..expect.to 不存在(但 expect(...).to 存在)
  • 啊——抱歉……(我是本地的“应该”用户)。谢谢指正!
【解决方案5】:

2017 回答如果您需要使用异步代码进行此操作:使用 await 并且 不需要任何其他库

it('Returns a correct error response when making a broken order', async function(){
  this.timeout(5 * 1000);
  var badOrder = {}
  try {
    var result = await foo.newOrder(badOrder)
    // The line will only be hit if no error is thrown above!
    throw new Error(`Expected an error and didn't get one!`)
  } catch(err) {
    var expected = `Missing required field`
    assert.equal(err.message, expected)
  }
});

请注意,发帖者只是在做同步代码,但我预计很多使用异步的人都会被问题标题引导到这里!

【讨论】:

  • 这对我来说没有意义。问题是关于构造函数的问题,它总是同步的,所以不需要 async/await。接下来就不用在try中抛出错误了,只需将assert代码放在finally中即可。
  • @CodeBling 当然同意,提问者问的是一些同步代码,但是标题“在 mocha 中测试预期的失败”导致了一大群需要测试大部分 JS 的人代码,即异步,因此赞成。
  • 这很公平,也许投反对票有点苛刻。如果明确await 仅对异步测试有帮助,仍然认为答案会更有用。在编辑答案之前投票已锁定,但我愿意更改它
【解决方案6】:

Mocha 默认使用来自 node.js (https://nodejs.org/api/assert.html) 的 Assert。您不需要任何外部库来检查方法是否引发错误。

Assert 有一个方法 - assert.throws,它有三个参数,但这里只有两个真正重要:

  • 函数 - 这里传递函数,不是函数调用
  • 错误 - 此处传递或对象构造函数或函数用于检查错误

假设您有一个名为sendMessage(message) 的函数,它在未设置消息参数时抛出错误。功能代码:

function sendMessage(message) {
  if (!message || typeof message !== 'string') {
     throw new Error('Wrong message');
  }
  // rest of function
}

好的,所以为了测试它,你需要额外的函数来覆盖输入。为什么?因为assert.throws 不给任何机会向要测试的函数传递参数。

所以不是

// WRONG
assert.throws(sendMessage, Error); // THIS IS WRONG! NO POSSIBILITY TO PASS ANYTHING

你需要创建匿名函数:

// CORRECT
assert.throws(() => {
  sendMessage(12);  // usage of wanted function with test parameters
}, Error)

你能看出区别吗?我没有直接传递函数,而是将函数调用放在匿名函数中,目的是使用准备好的输入调用它。

第二个参数呢。这取决于应该抛出什么样的错误,在上面的例子中Error对象被抛出,所以我不得不把Error放在那里。在此操作的结果中,assert.throws 比较抛出的对象是否是相同类型的对象。如果不是Error 会抛出不同的东西,那么这部分需要更改。例如,我将抛出 String 类型的值,而不是 Error

function sendMessage(message) {
  if (!message || typeof message !== 'string') {
     throw 'Wrong message'; // change to String
  }
  // rest of function
}

现在是测试调用

assert.throws(() => {
  sendMessage(12); // usage of wanted function with test parameters
}, (err) => err === 'Wrong message')

我使用比较函数代替第二个参数中的Error,以便将抛出的错误与预期进行比较。

【讨论】:

    【解决方案7】:

    throw (ES2016)

    http://chaijs.com/api/bdd/#method_throw

    为清楚起见... 这行得通

    it('Should fail if ...', done => {
        let ret = () => {
            MyModule.myFunction(myArg);
        };
        expect(ret).to.throw();
        done();
    });
    

    这行不通

    it('Should fail if ...', done => {
        let ret = MyModule.myFunction(myArg);
        expect(ret).to.throw();
        done();
    });
    

    【讨论】:

      【解决方案8】:

      MarkJ 接受的答案是比其他人更简单的方法。 让我在现实世界中举个例子:

      function fn(arg) {
        if (typeof arg !== 'string')
          throw TypeError('Must be an string')
      
        return { arg: arg }
      }
      
      describe('#fn', function () {
        it('empty arg throw error', function () {
          expect(function () {
            new fn()
          }).to.throw(TypeError)
        })
      
        it('non-string arg throw error', function () {
          expect(function () {
            new fn(2)
          }).to.throw(TypeError)
        })
      
        it('string arg return instance { arg: <arg> }', function () {
          expect(new fn('str').arg).to.be.equal('str')
        })
      })
      

      【讨论】:

        【解决方案9】:

        如果您不想将大量源代码包装到 expect 参数中,或者如果您有很多参数要传递并且它变得丑陋,您仍然可以使用原始语法通过利用提供的done 参数(但最初被忽略):

        it('should throw exception when instantiated', function(done: Done) {
          try {
            new ErrorThrowingObject();
            done(new Error(`Force the test to fail since error wasn't thrown`));
          }
          catch (error) {
            // Constructor threw Error, so test succeeded.
            done();
          }
        }
        

        因为您在这里使用done,它允许您在try 中执行上面的任意代码,然后准确指定您希望在源代码中记录失败的位置。

        通常,有人可能会尝试throwassert(false),但这些都将被trycatch 捕获,并导致您进行一些元检查以确定您的错误是否捕获的是您的测试中的预期错误,或者是您的测试失败的最终确定。那只是一团糟。

        【讨论】:

          猜你喜欢
          • 2023-03-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-03-23
          • 2021-12-31
          • 1970-01-01
          • 2015-11-21
          • 1970-01-01
          相关资源
          最近更新 更多