首页 > 解决方案 > 测试承诺链与异步等待 [mocha/chai/sinon]

问题描述

所以我是测试新手,并且已经设置了这个模拟数据库调用失败的方法的基本测试(对不起,如果我的术语不太正确)

我正在使用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();
})

我的问题是我的大部分代码都是使用承诺链编写的:

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
    });

这不起作用,我的(不必要的)返回语句也无济于事。

但是,使用重写方法async await确实有效(见下文)。但是,我想避免重写我的所有代码,并且很高兴了解这里的区别。

我最好的猜测是,与其让 sinon 存根抛出错误,不如让它拒绝承诺?我只是不完全确定这是否正确,或者如何实现。我有点在不知道的文档中磕磕绊绊

任何帮助表示赞赏,

谢谢,

缺口

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;
    } 
};

标签: javascriptunit-testingmocha.jssinon

解决方案


所以我想我找到了答案:

sinon 中的 stub 需要返回一个被拒绝的 Promise,而不是抛出一个错误:

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

Afaik 这是因为您不能真正在异步代码中抛出错误。

您正在测试的方法中的 Promise 链(在我的例子中是“getJobs”)需要返回该承诺。

所以而不是

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

            next(err);
            return err;
        });

利用

   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;

此外,测试中的异步函数需要返回或等待,以便 mocha 知道等待。使用done()对我不起作用:

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

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

Job.findAndCountAll.restore();

希望对某人有所帮助

**编辑:如下所述,我忘记done作为参数传递,这就是该方法不起作用的原因


推荐阅读