node.js - Nodejs - Mocha、Chai 多重异步测试

标签 node.js unit-testing mocha.js chai node-async

在这里完成 NodeJS 测试。尝试单独测试通过我的 API 调用的函数(这意味着,我想单独测试这些函数本身,而不是向特定端点发出 http 请求,该端点通常会调用多个函数,这些函数又向不同的第三方 API 发出请求)。它们的调用方式是我为每个数据源(数据源 = 第三方 API)构建了一个类,每个类包含具有相同签名的相同函数 - getDataconvertData,并返回带有结果的回调。

我还创建了一个模块,该模块创建许多 user 模拟,因为每个用户上下文返回不同的数据(这意味着,用户对象被输入到 getData 中,后者使用某些 user 属性来确定应返回哪些数据)。

我想要测试这一点的方法是创建大量模拟,然后为每个模拟运行函数。这是我到目前为止所得到的:

// Data sources to iterate over. Each is a class instance acquired through "require".
var dataSources = [
    source1,
    source2,
    source3,
    source4
];

describe('getData', function() {       
    this.timeout(10000);
    describe('per data source,', function() {
        context('standard call', function() {

            // Associative array to hold the data returned, a key for each data source.
            var finalResults = {};

            // Iterate over all data sources
            _.forEach(dataSources, function(dataSource) {

                // Generate user mocks
                var users = userMocks(10);

                // Iterate over all users. 
                _.forEach(users, function (user) {

                    // Call each data source with each of the users.
                    // Numbers of calls to make - (users * data-sources), so in this case - 10*4.
                    dataSource.getData(user, function (err, data) {
                        if (err) return done(err);

                        // Convert the data returned to my format
                        dataSource.convertData(data, function (err, processedData) {
                            if (err) return done(err);

                            // Populate finalResults with converted data from each source
                            if (finalResults[dataSource.sourceName]) {
                                finalResults[dataSource.sourceName] = finalResults[dataSource.sourceName].concat(processedData);
                            } else {
                                finalResults[dataSource.sourceName] = processedData;
                            }
                        });
                    });
                });
            });

            it('should return something', function(done) {
                _.forEach(finalResults.keys, function(key) {
                    expect(finalResults[key]).to.not.be.empty;
                    expect(finalResults[key].length).to.be.greaterThan(0);
                });
                setTimeout(function() {
                    done();
                }, 10000);
            })
        });
     });
});

});`

这是可行的(或者至少在查询有效时测试通过,这就是我想要的),但它很麻烦并且(非常)远非优雅或有效,特别是使用超时而不是使用 promise ,某种异步,或者可能是我还不熟悉的不同替代方案。

由于我发现的大多数资源( http://alanhollis.com/node-js-testing-a-node-js-api-with-mocha-async-and-should/https://developmentnow.com/2015/02/05/make-your-node-js-api-bulletproof-how-to-test-with-mocha-chai-and-supertest/https://justinbellamy.com/testing-async-code-with-mocha/ ,仅举几例)讨论直接 API 测试而不是特定的异步函数,因此我很乐意从更有经验的 Node 那里获得一些输入/最佳实践技巧。

最佳答案

您需要知道一堆异步操作何时完成。优雅的测试方法是使用 Promise 和 Promise 聚合:

Promise.all([ promise1, promise2, promise3 ]).then(function(results) {
  // all my promises are fulfilled here, and results is an array of results
});

使用 bluebird 将您的 dataSources 包装到 Promise 中。您不需要自行修改测试代码,bluebird提供了便捷的方法:

var Promise = require('bluebird')
var dataSources = [
    source1,
    source2,
    source3,
    source4
].map(Promise.promisifyAll);

使用新 promise 的函数为每个调用创建 promise :

   context('standard call', function() {
        var finalResults = {};
        var promiseOfResults = datasources.map(function(dataSource) {
            var users = userMocks(10);
            // Promise.all will take an array of promises and return a promise that is fulfilled then all of promises are
            return Promise.all( users.map(function(user) {
                // *Async functions are generated by bluebird, via Promise.promisifyAll
                return dataSource.getDataAsync(user)
                     .then(dataSource.convertDataAsync)
                     .then(function(processedData) {
                        if (finalResults[dataSource.sourceName]) {
                            finalResults[dataSource.sourceName] = finalResults[dataSource.sourceName].concat(processedData);
                        } else {
                            finalResults[dataSource.sourceName] = processedData;
                        }
                    });
            });
        });
        // promiseOfResults consists now of array of agregated promises
        it('should return something', function(done) {
            // Promise.all agregates all od your 'datasource' promises and is fulfilled when all of them are
            // You don't need the promise result here, since you agegated finalResults yourself
            return Promise.all( promiseOfResults ).then(function() {
                _.forEach(finalResults.keys, function(key) {
                    expect(finalResults[key]).to.not.be.empty;
                    expect(finalResults[key].length).to.be.greaterThan(0);
                });
                done();
            });
        });

测试的其余部分应使用相同的Promise.all(promiseOfResults),除非您需要一组新的结果。

关于node.js - Nodejs - Mocha、Chai 多重异步测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35679961/

相关文章:

node.js - 使用 Docker 作为微服务的服务注册中心

node.js - PM2 - 使用 NodeJS 参数运行 Coffeescript 文件

unit-testing - 测试什么以及何时测试?

javascript - Babel-node + mocha + babel-istanbul,意外的保留字 'import'

mocha.js - 'npm run coverage' 没有更新 lcov.info 文件

javascript - 如何在 Chai 中转换 ES6 导入?

javascript - 等待函数输出不超过一定时间的最佳方法是什么?

javascript - 使用nodejs时多次调用redis客户端的连接事件

unit-testing - 为什么在单元测试中,域类的逻辑之前和之后会收到 “No such property”?

java - Android - 单元测试无法引用 Android 类