【问题标题】:Run async code before entire mocha test在整个 mocha 测试之前运行异步代码
【发布时间】:2015-11-28 18:18:51
【问题描述】:

我正在寻找一种在整个 mocha 测试之前运行异步代码的方法。

这是一个测试示例,它使用参数和期望数组,并循环遍历该数组中的所有项以生成函数断言。

var assert = require('assert')

/* global describe, it*/

var fn = function (value) {
  return value + ' ' + 'pancake'
}

var tests = [
  {
    'arg': 'kitty',
    'expect': 'kitty pancake'
  },
  {
    'arg': 'doggy',
    'expect': 'doggy pancake'
  },
]

describe('example', function () {
  tests.forEach(function (test) {
    it('should return ' + test.expect, function (){
      var value = fn(test.arg)
      assert.equal(value, test.expect)
    })
  })
})

现在,我的问题是,如果测试值来自承诺,这将如何工作,如下所示:

var assert = require('assert')
var Promise = require('bluebird')

/* global describe, it*/

var fn = function (value) {
  return value + ' ' + 'pancake'
}

function getTests () {
  return Promise.resolve('kitty pancake')
  .delay(500)
  .then(function (value) {
    return [
      {
        'arg': 'kitty',
        'expect': value
      },
      {
        'arg': 'doggy',
        'expect': 'doggy pancake'
      }
    ]
  })
}

getTests().then(function (tests) {
  describe('example', function () {
    tests.forEach(function (test) {
      it('should return ' + test.expect, function (){
        var value = fn(test.arg)
        assert.equal(value, test.expect)
      })
    })
  })  
})

也试过了:

describe('example', function () {
  getTests().then(function (tests) {
    tests.forEach(function (test) {
      it('should return ' + test.expect, function (){
        var value = fn(test.arg)
        assert.equal(value, test.expect)
      })
    })
  })
})

但是在这个示例中,没有任何测试运行,因为 mocha 无法识别 describe 语句,因为它在 promise 中。

before / beforeEach 无论如何都不会帮助以格式进行测试,除非这是一个 beforeTest 钩子,它将为 mocha 提供需要在之前运行的异步操作的知识整个测试。

【问题讨论】:

    标签: javascript node.js asynchronous promise mocha.js


    【解决方案1】:

    我会使用 async/await 和 delay option,如下所示:

    setTimeout(async () => {
    //get tests async
    const tests = await getTests()
    
    describe('example', async () => {
    
      tests.forEach((test) => {
       it(`test name: ${test.name} `, () => {
        console.log(test.name)
      })
     })
    })
    
    run()
    }, 1000)
    

    【讨论】:

    • 有没有办法应用延迟但在获取数据后立即运行测试?
    • 更新:这正是run 所做的。
    【解决方案2】:

    作为 Daniel Perez 方法的替代方法,您也可以use the command line switch --delay and start the tests on the first run() call。通过异步延迟run(),您可以预先异步注册describes 和its。但请注意,您只能调用一次run(),即只能在一个测试文件中调用。因此,我在./test/ 中创建了一个异步测试运行器,并在./testAsync/ 中创建了每个异步测试:

    // ./test/asyncRunner.js
    "use strict";
    
    const allAsyncPaths = [
      "test-featureA",
      "test-featureB",
    ].map(a => "../testAsync/" + a);
    
    const allAsyncTestFunctions = allAsyncPaths.map(require);
    
    Promise.resolve({
    }).then(function() {
      const allPromises = allAsyncTestFunctions.map(a => a());
      return Promise.all(allPromises);
    }).then(function() {
      run(); // mocha waits for run() because of --delay flag
    }).catch(function(err) {
      console.error(err);
    });
    

    // ./testAsync/test-featureA.js
    "use strict";
    function asyncTestRegistrator() {
    
      return Promise.resolve({
      }).then(function() {
        return getTestsAsync();
      }).then(function(tests) {
    
      describe('example', function () {
        tests.forEach(function (test) {
          it('should return ' + test.expect, function (){
            var value = fn(test.arg);
            assert.equal(value, test.expect);
          });
        });
      });
    }
    module.exports = asyncTestRegistrator;
    

    【讨论】:

      【解决方案3】:

      我会在it 调用中移动异步逻辑。对单元测试过于花哨是一种代码味道,并且可能只会激怒其他开发人员,因为他们不仅必须调试和修复失败的测试,而且必须调试和修复甚至没有定义和运行的测试,因为花哨的设置代码有错误.尽量不要去那里。

      var assert = require('assert')
      var Promise = require('bluebird')
      
      /* global describe, it*/
      
      var fn = function(value) {
        return value + ' ' + 'pancake'
      }
      
      function getTests() {
        return Promise.resolve('kitty pancake')
          .delay(500)
          .then(function(value) {
            return [
              {
                'arg': 'kitty',
                'expect': value
              },
              {
                'arg': 'doggy',
                'expect': 'doggy pancake'
              }
            ]
          })
      }
      
      describe('example', function() {
        it('should handle many things', function(done) {
          getTests().then(function(tests) {
            tests.forEach(function(test) {
              var value = fn(test.arg)
              assert.equal(value, test.expect, 'should return ' + test.expect)
            })
            done()
          })
        })
      })
      

      【讨论】:

      • 我喜欢这个解决方案,它看起来很简单,但是如果我正在运行的断言成功,则缺少发出 it 语句不会为我提供任何信息。
      【解决方案4】:

      我不确定是否有任何简单的方法可以做到这一点,但您可以尝试run Mocha programatically

      这是一个有点脏的版本,只是为了展示这个想法。

      data.js

      var Promise = require('bluebird')
      
      module.exports.tests = []
      
      function getTests () {
        return Promise.resolve('kitty pancake')
        .delay(500)
        .then(function (value) {
           module.exports.tests = [
            {
              'arg': 'kitty',
              'expect': value
            },
            {
              'arg': 'doggy',
              'expect': 'doggy pancake'
            }
          ]
        })
      }
      
      module.exports.getTests = getTests
      

      test-launcher.js

      var Mocha = require('mocha'),
          fs = require('fs'),
          path = require('path')
      
      // First, you need to instantiate a Mocha instance.
      var mocha = new Mocha()
      
      // Then, you need to use the method "addFile" on the mocha
      // object for each file.
      
      // Here is an example:
      fs.readdirSync('test').filter(function(file){
          // Only keep the .js files
          return file.substr(-3) === '.js'
      
      }).forEach(function(file){
          // Use the method "addFile" to add the file to mocha
          mocha.addFile(
              path.join('test', file)
          )
      })
      
      // make sure your tests are loaded before running the tests
      require('./data').getTests().then(function () {
      
        // Now, you can run the tests.
        mocha.run(function(failures){
          process.on('exit', function () {
            process.exit(failures)
          })
        })
      })
      

      test/index.js

      var assert = require('assert')
      
      var tests = require('../data').tests
      
      var fn = function (value) {
        return value + ' ' + 'pancake'
      }
      
      describe('test', function () {
        describe('example', function () {
          tests.forEach(function (test) {
            it('should return ' + test.expect, function (){
              var value = fn(test.arg)
              assert.equal(value, test.expect)
            })
          })
        })
      })
      

      然后你可以通过运行test-launcher.js 来运行你的休息。

      【讨论】:

      • 这将如何保存在test 文件夹中?当我运行mocha 和代码覆盖率时,我需要它与其他测试很好地配合吗?
      • 只有测试应该存在于test 文件夹中,test-launcher.js 应该位于项目的根目录中,或者包含其他实用程序(如果有的话)的目录中。代码覆盖率应该非常好,例如,在伊斯坦布尔,istanbul cover test-launcher.js 应该给你你想要的。我创建了一个具有代码覆盖率的示例项目,看看它。 github.com/tuvistavie/mocha-async-test
      猜你喜欢
      • 2016-11-30
      • 2018-09-22
      • 2020-06-22
      • 1970-01-01
      • 2014-10-21
      • 2015-09-16
      • 1970-01-01
      • 2016-08-07
      • 1970-01-01
      相关资源
      最近更新 更多