简体   繁体   English

测试承诺链与异步等待 [mocha/chai/sinon]

[英]Testing promise chains vs async await [mocha/chai/sinon]

So I'm new to testing and have set up this basic test of a method that mocks the failure of a database call (sorry if my terminology isn't quite right)所以我是测试新手,并且已经设置了一个模拟数据库调用失败的方法的基本测试(对不起,如果我的术语不太正确)

I'm using sequelize, so Job is a model and findAndCountAll a related method.我正在使用 sequelize,所以Job是一个模型,而findAndCountAll是一个相关的方法。

it('Should throw a 500 error if accessing the DB fails', () => {
    sinon.stub(Job, 'findAndCountAll');
    Job.findAndCountAll.throws();

    const req = {
        query: {
            index: 0,
            limit: 10,
            orderField: 'createdAt',
            order: 'DESC'
        }
    };

    adminController.getJobs(req, {}, () => {}).then(result => {
            expect(result).to.be.an('error');
            expect(result).to.have.property('statusCode', 500);

            done();
        })

    Job.findAndCountAll.restore();
})

My problem is that most of my code is written using promise chaining:我的问题是我的大部分代码都是使用承诺链编写的:

exports.getJobs = (req, res, next) => {
    const index = req.query.index || 0;
    const limit = req.query.limit || 10;
    const orderField = req.query.orderField || 'createdAt';
    const order = req.query.orderDirection || 'DESC';
 
    Job.findAndCountAll({
        // ...arguments
    })
    .then(results => {
        res.status(200).json({ jobs: results.rows, total: results.count });
        return // Attempted to add a return statement to enter the .then() block in the test
    })
    .catch(err => {
        if(!err.statusCode) err.statusCode = 500;

        next(err);
        return err; // Attempted to return the error to enter the .then() block in the test
    });

This doesn't work, and my (unecessary) return statements don't help either.这不起作用,我的(不必要的)返回语句也无济于事。

However, rewriting the method using async await does work (see below).但是,使用async await重写方法确实有效(见下文)。 However I'd like to avoid rewriting all my code, and it would be nice to understand the difference here.但是我想避免重写我的所有代码,如果能理解这里的区别会很好。

My best guess is that rather than getting the sinon stub to throw an error, I should have it reject the promise?我最好的猜测是,与其让 sinon 存根抛出错误,不如让它拒绝承诺? I'm just not entirely sure whether that's along the right lines or not, or how to achieve it.我只是不完全确定这是否正确,或者如何实现它。 I'm kind of stumbling round the docs not really knowing我有点绊倒文档并不真正知道

Any help appreciated,任何帮助表示赞赏,

Thanks,谢谢,

Nick缺口

exports.getJobs = async(req, res, next) => {
    const index = req.query.index || 0;
    const limit = req.query.limit || 10;
    const orderField = req.query.orderField || 'createdAt';
    const order = req.query.orderDirection || 'DESC';

    try {
        const results = await Job.findAndCountAll({ //...params });

        // ... 

        res.status(200).json({ jobs: results.rows, total: results.count });
        return;
    } catch(err) {
        if(!err.statusCode) err.statusCode = 500;
        next(err);
        return err;
    } 
};

So I think I found the answer:所以我想我找到了答案:

The stub in sinon needs to return a rejected promise, rather than throwing an error: sinon 中的存根需要返回一个被拒绝的承诺,而不是抛出一个错误:

sinon.stub(Job, 'findAndCountAll');
Job.findAndCountAll.rejects();

Afaik this is because you can't really throw an error in async code. Afaik 这是因为你不能真正在异步代码中抛出错误。

And the Promise chain in the method you're testing (in my case 'getJobs'), needs to return that promise.您正在测试的方法中的 Promise 链(在我的例子中是“getJobs”),需要返回该承诺。

So instead of所以代替

  Job.findAndCountAll({
            // ...arguments
        })
        .then(results => {
            res.status(200).json({...});
            return;
        })
        .catch(err => {
            if(!err.statusCode) err.statusCode = 500;

            next(err);
            return err;
        });

Use采用

   const results = Job.findAndCountAll({
            // ...arguments
        })
        .then(results => {
            res.status(200).json({...});
            return;
        })
        .catch(err => {
            if(!err.statusCode) err.statusCode = 500;

            next(err);
            return err;
        });
   return results;

Also, the async function in the test needs to either be returned, or awaited, so that mocha knows to wait.此外,测试中的异步函数需要返回或等待,以便 mocha 知道等待。 Using done() didn't work for me:使用done()对我不起作用:

const result = await adminController.getJobs(req, {}, () => {});

expect(result).to.be.an('error');
expect(result).to.have.property('statusCode', 500);

Job.findAndCountAll.restore();

Hope that helps someone希望能帮助某人

**edit: as mentioned below, I forgot to pass done as an argument, which is why that method didn't work **编辑:如下所述,我忘记将done作为参数传递,这就是该方法不起作用的原因

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM