【问题标题】:Testing synchronous code测试同步代码
【发布时间】:2015-06-06 12:49:07
【问题描述】:

我有一段代码使用node-sync,如下所示:

function funcA() {
  return new Promise(function(resolve, reject) {
    Sync(function () {
      return funcB.sync();
    }, function (err, result) {
      if(err) {
        reject(err);
      } else {
        resolve(result);
      }
    });
}

这段代码是用mocha+chai测试的:

it("should return array", function() {
  return funcA().then(function(result) {
    expect(result).to.be.an.instanceof(Array);
  });
});

几个月前它工作得很好,但现在这个测试总是超时:

错误:超过 2000 毫秒的超时。确保在此测试中调用了 done() 回调。

到目前为止我已经尝试过:

  • 使用 done() 而不是返回承诺
  • node-sync 替换为synchronize.js
  • 增加超时

我发现,这个测试的 expect(... 部分实际上是被调用的,但只是在 mocha 杀死测试之后。无论当前设置什么超时间隔,在我收到 Error: timeout 消息后,expect(.. 总是会被调用约 20 毫秒。

我通过在测试文件顶部添加setInterval(function(){}, 10) 解决了这个问题。 我想知道为什么会这样,是否有更好的方法来解决这个问题?

[编辑] 看起来这是一个特定于节点版本的问题。测试在 0.12.4 上失败,但在 0.10.38 上正常运行。

[编辑] 实际代码可用here

【问题讨论】:

  • 看起来很奇怪..我可以重现它,但无法弄清楚问题所在。可能是一个很长的镜头,但可能会深入研究 node-sync ,请参阅这些 github 票 herehere
  • 顺便说一句,最好不要在测试中异步运行代码(恕我直言)。我知道您正在尝试运行此块同步,但也许可以尝试 chai-as-promised 模块,以便您可以删除 done

标签: node.js mocha.js


【解决方案1】:

根据您的code,我假设您的 funcB 函数正在以同步方式运行代码。

所以当我以这种方式创建 funcB 时:

function funcB() {
  return [1, 2, 3];
}

并运行测试,Mocha 报错:

错误:超过 2000 毫秒的超时。确保在此测试中调用了 done() 回调。

但如果我将 异步函数 中的 funcB 转换为:

function funcB(cb) {
  process.nextTick(function () {
    cb(null, [1, 2, 3]);
  });
}

Mocha 运行测试没有任何问题:

✓ 应该返回一个数组


所以我运行正常的完整代码(注释的 funcB 是会导致错误的代码)是这样的:

// install dependencies
// npm install promise
// npm install sync
var Promise = require('promise');
var assert = require('assert');
var Sync = require('sync');

function funcA() {
  return new Promise(function (resolve, reject) {
    Sync(function () {
      return funcB.sync();
    }, function (err, result) {
      if (err) {
        reject(err);
      } else {
        resolve(result);
      }
    });
  });
}

// function funcB() {
//   return [1, 2, 3];
// }

function funcB(cb) {
  process.nextTick(function () {
    cb(null, [1, 2, 3]);
  });
}

it("should return an array", function(done) {
  return funcA().then(
    function (result) {
      console.log(result);
      assert.equal(Array.isArray(result), true);
      done();
    }
  );
});

所以我认为我认为误用由同步库创建的sync method(在同步函数上使用它)是导致此问题的原因。

【讨论】:

  • 嘿威尔逊!谢谢你,但它仍然是一个黑客,它没有回答为什么会发生这种情况。我猜我对setInterval 的使用与您的nextTick hack 的用途完全相同。似乎节点“睡着了”,需要被nextTicksetInterval 唤醒。问题是,为什么会发生这种情况,这是节点问题、同步问题还是预期行为?我很想弄清楚这一点。
  • 也许我错了,但从method 的文档中推断:“sync() 方法只是将任何异步函数转换为同步函数” 所以调用此方法来自 funcB 之类的同步函数,对我来说可能是错误的根源。
【解决方案2】:

您可能只是错过了done() 回调:

it("should return array", function(done) {
    funcA().then(function(result) {
        expect(result).to.be.an.instanceof(Array);
        done();
    });
});

http://mochajs.org/#asynchronous-code

【讨论】:

  • 嘿,感谢您的建议 - 正如问题中提到的那样,我已经尝试过 done()。此外,返回一个承诺应该工作得很好(事实上你链接到摩卡文档中描述的那个部分)。我的问题似乎与节点版本相关。
【解决方案3】:

您可以对 mocha 可执行文件使用超时参数。

例如,如果您想要 500 毫秒的超时,只需将您的 package.json 更改为:

"scripts": {
    "test": "mocha specs --timeout 500 --require specs/helpers/chai.js"
},

也许你的承诺被拒绝了,所以你必须使用catch方法调用done

it("should return array", function(done) {
    return funcA().then(function(result) {
        expect(result).to.be.an.instanceof(Array);
        done();
    }).catch(done);
});

这也将帮助您调试承诺代码中可能发生的最终错误。

【讨论】:

  • 嘿!如问题中所述,我尝试增加超时 - 测试在超时后 总是 失败(无论超时值是多少)。有 catch 是一个很好的提示,但是这个测试不会失败,它会超时。
  • @KonradDzwinel 嗯.. 似乎您正在尝试使用在同一过程中完成所有事情的承诺来测试代码。尝试将 setTimeout() 更改为 process.nextTick(); 并检查它是否仍然有效。另外,您可以发送您要测试的方法的代码吗?
  • 嘿!整个事情都可用here。测试在节点 0.10 上通过,但在 0.12 上失败。稍后我将尝试将 setInterval 更改为 nextTick。我的猜测是它会起作用 - 问题是为什么我必须在节点 0.12 中手动触发下一个刻度?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-25
  • 1970-01-01
  • 1970-01-01
  • 2016-07-31
  • 2014-09-29
  • 2012-01-18
  • 1970-01-01
相关资源
最近更新 更多