【问题标题】:Testing a multitude of data asynchronously in Mocha在 Mocha 中异步测试大量数据
【发布时间】:2013-01-17 17:36:13
【问题描述】:

我需要遍历电子邮件列表并检查它们是否有效。如果验证失败,我会抛出一个错误让 Mocha 知道。

it('validates valid email addresses', function (done) {
  [
    'oliverash@me.com',
    'oliver.ash@me.com',
    'oliver-ash@me.com',
    'oliver+ash@me.com',
    'oliver\'s-email@me.com'
  ].forEach(function (value) {
    user.email = value

    user.validate(function (err) {
      // Failed to validate, throw an error
      if (err) {
        throw new Error()
      }
    })
  })

  // All documents validated, so call `done`
  done()
})

但是,此代码似乎无法正常工作 - 只有数组中的最后一封电子邮件无效。

我做错了什么?

【问题讨论】:

    标签: node.js unit-testing testing mongoose mocha.js


    【解决方案1】:

    您可以使用 async 实用程序库来简化异步循环。

    it('validates valid email addresses', function (done) {
      async.forEach([
        'oliverash@me.com',
        'oliver.ash@me.com',
        'oliver-ash@me.com',
        'oliver+ash@me.com',
        'oliver\'s-email@me.com'
      ], 
      function (value, callback) {
        user.email = value
        user.validate(callback)
      },
      function (err) {
        if (err) {
          throw new Error()
        }
        done()
      })
    })
    

    第一个函数在数组中的每个元素上调用,它有两个参数:数组中的项和一个回调函数。如果回调收到错误,它会立即停止迭代。一旦数组中的所有项都完成(或其中任何一项都返回错误),就会调用最终函数。在这个例子中,它要么抛出错误,要么运行 Mocha done 函数。

    readme for async 很好地解释了 forEach 函数的工作原理。

    【讨论】:

    • 这看起来很有希望,尽管我仍然有只计算最后一个电子邮件地址的问题。如果其他任何一个无效,测试仍将通过。验证本身很好,问题出在测试。
    • 事实证明,这是因为我不希望循环迭代并行发生。我想,我需要它们一个接一个地发生。这是因为user.email = value 等于数组中的最后一项,如果这有意义的话。
    • 如果仅用于单元测试,您可以将forEach 替换为forEachSeries 以使所有内容同步并避免始终使用最后一封电子邮件收到user.email
    • 是的!那很完美。谢谢你。我认为我仍然需要使用async
    • 显然。 forEachSeriesasync 的一部分。此外,async 是一个很棒的库,您在处理异步代码时应该使用它,它将为您省去很多麻烦:)
    【解决方案2】:

    如果你的user.validate函数是异步的,你的forEach调用不会等待user.validate的回调调用。

    这意味着您的 forEach 函数将在 user.validate 调用所有回调之前结束,并将在每次验证结束之前调用 done()

    您应该使用forEach 函数的所有参数并在user.validate 回调中调用done()。我将添加一个计数变量来计数调用的回调,并知道何时需要调用done() 函数。

    it('validates valid email addresses', function (done) {
      var count = 0;     // count variable
      [
        'oliverash@me.com',
        'oliver.ash@me.com',
        'oliver-ash@me.com',
        'oliver+ash@me.com',
        'oliver\'s-email@me.com'
      ].forEach(function (value, index, array) {
        user.email = value;
    
        user.validate(function (err) {
          ++count;      // Callback called, we add +1 to count.
          if (err) {
            throw new Error();
          }
          // Check if all callbacks have been called and call done if true.
          if (count === array.length)
            done();
        });
    
      });
    
    })
    

    这应该会更好。我没有测试它,但它应该可以工作。

    PS:请不要忘记分号。在某些情况下,它会给你带来不确定的行为,不放它们是一个坏习惯(我们是程序员!)。

    编辑 - 2013 年 8 月 6 日:刚刚阅读了一些关于 Javascript 中分号的内容并记住了这个线程,这就是为什么你应该在代码中添加分号:http://bonsaiden.github.io/JavaScript-Garden/#core.semicolon

    【讨论】:

    • 感谢您的解释。在这里,done 仍然会调用,即使在较早的迭代中抛出了错误,这意味着测试将始终通过。我想我必须设置另一个标志来规避它?我也使用index 而不是count——效率更高。
    • P.S.没有分号是我选择的编码风格。用 JS 做的很好。
    • 嗯,你明白了。我不使用索引,因为有时索引4 的回调会在索引0 的回调之前被调用,这意味着你会遇到同样的问题。您无法知道回调何时会被调用以及它们是否会以正确的顺序被调用。事实上,done() 只有在没有回调抛出 new Error() 时才会被调用,因为我们在尝试调用 done () 之前会检查它。如果抛出new Error(),则执行停止,Mocha 将通过it() 调用捕获错误并结束测试。否则,你打电话给done() 一切都很好!
    • 嗯,好的。那么这个测试是怎么通过的呢?如果无效电子邮件是数组中的最后一个,它似乎只会捕获验证错误。 gist.github.com/4697762/…
    猜你喜欢
    • 2014-02-08
    • 2012-08-22
    • 2012-09-29
    • 1970-01-01
    • 2020-03-26
    • 1970-01-01
    • 1970-01-01
    • 2018-03-06
    • 1970-01-01
    相关资源
    最近更新 更多