有没有办法让Chai使用异步Mocha测试?

Tho*_*low 79 javascript unit-testing mocha.js

我正在使用浏览器运行器在Mocha中运行一些异步测试,我正在尝试使用Chai的期望样式断言:

window.expect = chai.expect;
describe('my test', function() {
  it('should do something', function (done) {
    setTimeout(function () {
      expect(true).to.equal(false);
    }, 100);
  }
}
Run Code Online (Sandbox Code Playgroud)

这不会给我正常的失败断言消息,而是我得到:

Error: the string "Uncaught AssertionError: expected true to equal false" was thrown, throw an Error :)
    at Runner.fail (http://localhost:8000/tests/integration/mocha/vendor/mocha.js:3475:11)
    at Runner.uncaught (http://localhost:8000/tests/integration/mocha/vendor/mocha.js:3748:8)
    at uncaught (http://localhost:8000/tests/integration/mocha/vendor/mocha.js:3778:10)
Run Code Online (Sandbox Code Playgroud)

所以它显然正在捕捉错误,它只是没有正确显示它.任何想法如何做到这一点?我想我可以用一个错误对象调用"完成",但后来我失去了像柴这样的东西的所有优雅,它变得非常笨重......

Jea*_*ent 94

您的异步测试会在失败的expect()操作上生成异常,it()因为异常被抛出了it()范围之外,因此无法捕获.

您看到的捕获的异常是使用process.on('uncaughtException')under node或window.onerror()在浏览器中使用捕获的.

要解决此问题,您需要在调用的异步函数中捕获异常setTimeout(),以便以done()异常作为第一个参数进行调用.您还需要调用done()没有参数来指示成功,否则mocha会报告超时错误,因为您的测试函数永远不会发出信号表示已完成:

window.expect = chai.expect;

describe( 'my test', function() {
  it( 'should do something', function ( done ) {
    // done() is provided by it() to indicate asynchronous completion
    // call done() with no parameter to indicate that it() is done() and successful
    // or with an error to indicate that it() failed
    setTimeout( function () {
      // Called from the event loop, not it()
      // So only the event loop could capture uncaught exceptions from here
      try {
        expect( true ).to.equal( false );
        done(); // success: call done with no parameter to indicate that it() is done()
      } catch( e ) {
        done( e ); // failure: call done with an error Object to indicate that it() failed
      }
    }, 100 );
    // returns immediately after setting timeout
    // so it() can no longer catch exception happening asynchronously
  }
}
Run Code Online (Sandbox Code Playgroud)

在所有测试用例上这样做很烦人,而不是干,所以你可能想要为你提供一个功能.我们叫这个函数check():

function check( done, f ) {
  try {
    f();
    done();
  } catch( e ) {
    done( e );
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,check()您可以按如下方式重写异步测试:

window.expect = chai.expect;

describe( 'my test', function() {
  it( 'should do something', function( done ) {
    setTimeout( function () {
      check( done, function() {
        expect( true ).to.equal( false );
      } );
    }, 100 );
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我正在努力解决这个问题,发现这篇博文非常有帮助:http://staxmanade.com/2015/11/testing-asyncronous-code-with-mochajs-and-es7-async-await/ (3认同)
  • 上面的答案似乎是错误的。失败的期望会立即抛出并以有意义的错误停止测试,无需复杂的try / catch。我刚刚通过浏览器测试对其进行了测试。 (2认同)

Ric*_*ter 19

以下是我对ES6/ES2015承诺和ES7/ES2016 async/await的通过测试.希望这为研究此主题的任何人提供了一个很好的更新答案:

import { expect } from 'chai'

describe('Mocha', () => {
  it('works synchronously', () => {
    expect(true).to.equal(true)
  })

  it('works ansyncronously', done => {
    setTimeout(() => {
      expect(true).to.equal(true)
      done()
    }, 4)
  })

  it('throws errors synchronously', () => {
    return true
    throw new Error('it works')
  })

  it('throws errors ansyncronously', done => {
    setTimeout(() => {
      return done()
      done(new Error('it works'))
    }, 4)
  })

  it('uses promises', () => {
    var testPromise = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('Hello')
      }, 4)
    })

    testPromise.then(result => {
      expect(result).to.equal('Hello')
    }, reason => {
      throw new Error(reason)
    })
  })

  it('uses es7 async/await', async (done) => {
    const testPromise = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('Hello')
      }, 4)
    })

    try {
      const result = await testPromise
      expect(result).to.equal('Hello')
      done()
    } catch(err) {
      done(err)
    }
  })

  /*
  *  Higher-order function for use with async/await (last test)
  */
  const mochaAsync = fn => {
    return async (done) => {
      try {
        await fn()
        done()
      } catch (err) {
        done(err)
      }
    }
  }

  it('uses a higher order function wrap around async', mochaAsync(async () => {
    const testPromise = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('Hello')
      }, 4)
    })

    expect(await testPromise).to.equal('Hello')
  }))
})
Run Code Online (Sandbox Code Playgroud)


xin*_*ink 13

如果你喜欢承诺,可以尝试Chai作为Promised + Q,它允许这样的东西:

doSomethingAsync().should.eventually.equal("foo").notify(done);
Run Code Online (Sandbox Code Playgroud)