NodeJS 信守承诺:单个测试中多个Expect语句

xzlaal3s  于 2022-12-12  发布在  Node.js
关注(0)|答案(5)|浏览(184)

我正在使用chai-as-promised来测试一些promise。我的问题是我不确定如何在一个测试中使用多个expect语句。为了使expect().to.be.fulfilled正常工作,我需要返回它,如下所示:

it('test', () => {
  return expect(promise).to.be.fulfilled
}

...或使用notify,如下所示:

it('test', (done) => {
  expect(promise).to.be.fulfilled.notify(done)
}

当我需要检查另一件事情时,就会出现这个问题,比如调用某个函数,如下所示:

it('test', (done) => {
  var promise = doSomething()
  expect(sinon_function_spy.callCount).to.equal(1)
  expect(promise).to.be.fulfilled.notify(done)
})

这里的问题是,因为doSomething()是异步的,所以当我调用expect时,对sinon_function_spy的调用可能还没有发生,这使得这个测试变得不可靠。如果我使用then,如下所示:

it('test', (done) => {
  var promise = doSomething()
  promise.then(() => {
    expect(sinon_function_spy.callCount).to.equal(1)
  })
  expect(promise).to.be.fulfilled.notify(done)
})

然后测试 * 从技术上讲 * 如预期的那样通过和失败,但是它将失败,因为由于then调用中抛出的异常,承诺被拒绝了。类似地,如果我有一个期望承诺被拒绝的情况:

it('test', (done) => {
  var promise = doSomething()
  promise.then(() => {
    expect(sinon_function_spy.callCount).to.equal(1)
  })
  expect(promise).to.be.rejected.notify(done)
})

那么sinon_function_spy上的检查永远不会被调用,因为承诺被拒绝了,并且不会调用then
如何使两个expect语句都可靠地执行并返回正确的值?

6mzjoqzu

6mzjoqzu1#

如果你使用mocha或jest作为测试框架,你可以在then()块中返回带有期望的promise:

it('test', () => {
   return doSomething().then( () => {
     expect(sinon_function_spy.callCount).to.equal(1);
   });
});

此测试将在成功完成承诺并且运行expect之后结束。如果您使用的是jasmine,则可以使用jasmine-promises包来获得相同的功能。
对于相反的情况,我建议创建一个 Package 器来颠倒承诺的极性:

function reverse( promise ) {
   //use a single then block to avoid issues with both callbacks triggering
   return promise.then(
       () => { throw new Error("Promise should not succeed"); }
       e => e; //resolves the promise with the rejection error
   );
}

现在你可以做

it('test', () => {
   return reverse( doSomethingWrong() ).then( error => {
       expect( error.message ).to.equal("Oh no");
   });
});
x0fgdtte

x0fgdtte2#

一种实现多重期望的方法

it('should fail if no auth', () => {
    const promise = chai.request(server).get('/albums');
    return expect(promise).to.be.rejected.then(() => {
      return promise.catch(err => {
        expect(err).not.to.be.null;
        expect(err.response).to.have.status(401);
        expect(err.response).to.be.a.json;
      });
   });
});
nlejzf6q

nlejzf6q3#

在想要AssertPromise已经实现 * 并且 * 一个调用已经按预期执行的情况下,你并不真的需要第一部分作为Assert。如果Promise拒绝,只要你返回它,摩卡测试用例本身就会失败:

it('test', () => {
  return doSomething()
    .then(() => {
      expect(sinon_function_spy.callCount).to.equal(1)
    });
});

如果doSomething()返回的Promise被拒绝,测试用例也将被拒绝。如果expectAssert失败,它也将使具有该失败Assert的测试用例失败。如果您想更明确一点:

it('test', () => {
  return doSomething()
    .then(() => {
      expect(sinon_function_spy.callCount).to.equal(1)
    }, err => {
      expect(err).to.not.exist;
    });
});

...您可以捕获错误。请注意,使用这种带有两个回调的then风格,在第一个回调中失败的Assert不会到达第二个回调,因此只有Mocha看到失败的Assert。
下面是你如何做一个预期失败的承诺:

it('test', () => {
  return doSomething()
    .then(() => {
      throw new Error('Promise should not have resolved');
    }, err => {
      expect(err).to.exist;
      expect(sinon_function_spy.callCount).to.equal(1)
    });
})
9o685dep

9o685dep4#

我发现的最好的方法是这样的:

it('test', async () => {
  await expect(promise1).to.eventually.be.equal(1);
  await expect(promise2).to.eventually.be.equal(2);
})
dz6r00yl

dz6r00yl5#

在一个测试中使用多个Assert的一个问题是,如果第一个Assert失败了,我们就不会得到其余Assert的反馈。在某些情况下,这可能很好,但如果你的需求要求你得到所有Assert的反馈,那么你就剩下几个选择了。
一个选择是看看是否可以使用Jasmine和Jasmine的Assert来代替Chai。默认情况下,Jasmine会检查并报告测试中的所有Assert,而Jasmine能够完成Mocha和Chai不能完成的任务。Jasmine的测试运行器和Assert库集成得更紧密,这也许就是为什么他们能够完成这项任务的原因。
如果Jasmine不是一个选项,那么另一个想法是将测试执行放在before块中,然后在单独的it块中验证每个Assert,这会产生更大的反馈,但是一些测试报告工具可能会将其报告为N个测试,而不是单个测试。
第三种选择是使用我构建并发布的名为multi-assert的Node.js模块,这允许在同一个测试中使用多个ChaiAssert(可能还有其他Assert库),并报告所有失败。

const { expect } = require('chai');
const { multiAssertAsync } = require('multi-assert');

describe('Test - async/promises', () => {
    
    async function fetchData() {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('{"status":"bluegreen"}');
            }, 300)
        });
    }

    it('should expect status to be yellowblue, yellowred, bluegreen, and 3 to equal 4', async () => {
        await multiAssertAsync([
            async () => expect((JSON.parse(await fetchData())).status).to.equal('yellowblue'),
            () => expect(3).to.equal(4),
            async () => expect((JSON.parse(await fetchData())).status).to.equal('bluegreen'),
            async () => expect((JSON.parse(await fetchData())).status).to.equal('yellowred')
        ]);
    });
});

在执行之后,我们看到第一个、第三个和第四个Assert失败,并报告代码中的各种缺陷,为开发人员和测试人员提供了最大的透明度和机会来完全修复代码。

1) Test - async/promises
       should expect status to be yellowblue, yellowred, bluegreen, and 3 to equal 4:
     AssertionError: 

      MultipleAssertionError: expected 3 to equal 4
        at /Users/user123/proj/multi-assert/examples/example-async.spec.js:17:32
        at /Users/user123/proj/multi-assert/multi-assert-async.js:12:27
        at Array.map (<anonymous>)

      MultipleAssertionError: expected 'bluegreen' to equal 'yellowblue'
        at /Users/user123/proj/multi-assert/examples/example-async.spec.js:16:75
        at async /Users/user123/proj/multi-assert/multi-assert-async.js:12:21
        at async Promise.all (index 0)

      MultipleAssertionError: expected 'bluegreen' to equal 'yellowred'
        at /Users/user123/proj/multi-assert/examples/example-async.spec.js:19:75
        at async /Users/user123/proj/multi-assert/multi-assert-async.js:12:21
        at async Promise.all (index 3)

      at /Users/user123/proj/multi-assert/multi-assert-async.js:22:23

我还没有尝试过使用.then语法,因为对我来说,async/await在很多情况下可能更可读,更容易理解。如果替代语法有任何问题,我很乐意提供帮助。希望这能有所帮助!

相关问题