9

我有这种摩卡测试:

describe 'sabah', →
    beforeEach →
        @sabahStrategy = _.filter(@strats, { name: 'sabah2' })[0]
            .strat

    it 'article list should be populated', (done) →
        @timeout 10000
        strat = new @sabahStrategy()
        articles = strat.getArticleStream('barlas')
        articles.take(2).toArray( (result)→
            _.each(result, (articleList) →

                // I make the assertions here
                // assert(false)
                assert(articleList.length > 1)
            )
            done()
        )

问题是,每当我这样做assert(false)时,测试都会挂起直到超时,而不是给出断言错误,为什么?

编辑:

例如,如果我有这两个测试

    it 'assert false', (done) →
        assert(false)
        done()

    it 'article link stream should be populated', (done) →
        @timeout 20000
        articles = @sabahStrategy.articleLinkStream('barlas')
        articles.pull((err, result)→
            console.log('here')
            assert(false)
            console.log('after')
            assert(!err)
            assert(result.length > 1);
            _.each(result, (articleList) →
                assert(articleList.link)
            )
            done()
        )

第一个,如预期的那样给出断言错误,第二个,logs here,并且挂起,assert(false)所以after永远不会记录。它与articles作为流有关,并且断言在pull回调中,这来自highland.js API

解决编辑

所以根据保罗的说法,我用这段代码解决了这个问题:

    it 'article stream should be populated', (done) →
        @timeout 30000
        articles = @sabahStrategy.articleStream('barlas')

        articles.pull((err, result) →
            try
                # assert false properly throws now.
                assert(false)
                assert(!err)
                assert(result.length == 1)
                assert(result[0].body)
                assert(result[0].title || result[0].title2)
                done()
            catch e
                done(e)
        )

编辑2

我已经制作了问题的简化版本:

h = require('highland')
Q = require('q')

describe 'testasynchigh', →
    beforeEach →
        @deferred = Q.defer()
        setTimeout((→
            @deferred.resolve(1)
        ).bind(this), 50)


    it 'should throw', (done) →
        s = h(@deferred.promise);
        s.pull((err, result) →
            console.log result
            assert false
            done()
        )

我看到你的版本确实有效@Louis,但如果你将承诺加入混合中,mocha 无法解决问题,所以它会在这个例子中挂起。还可以尝试注释掉assert false并查看它是否通过。

所以路易斯,我希望我能引起你的注意,你能解释一下这个问题吗,try catch看起来确实很丑,我希望你能找到一个合理的解决方案。

4

3 回答 3

12

因为这就是您告诉它您想要做的事情,当您添加“完成”回调时。

实际执行此测试的方法是return done(err)在断言失败时调用,其中 err 是您想要报告的任何字符串或错误对象。

首先,当您的断言失败时,程序会抛出异常并且永远不会到达done(),这就是为什么您没有看到 done 被调用的原因。这就是断言应该如何工作,但是由于您处于异步测试中,结果是回调永远不会触发,这就是您达到超时的原因。

其次,正如我最初的回答所说err,您想从测试中发出任何错误。它可以是字符串错误消息或完整的错误对象子类。您创建它然后传递它done()以指示测试失败。

在异步测试中构建代码的更好方法是将测试用作简单的布尔值,而不是断言。如果你真的想使用断言,那么将它包装在一个try..catch. 这里有几个例子:

if(err) return done(err); // in this case, err is defined as part of the parent callback signature that you have in your code already.

if(result.length < 1) return done('Result was empty!'); 

最后,如果你真的想要assert,那么你可以:

try{
  assert(!err);
}catch(e){
  return done(e);
}

我打电话return done(err)而不是done(err)因为它阻止其余代码执行,这通常是你想要的。

于 2014-11-07T04:21:29.353 回答
1

对于任何有同样问题的人:您应该确保done()即使在断言失败后也会调用它,如以下代码所示:

try {
  // your asserts go here
  done();
} catch (e) {
  done(e);
}
于 2015-12-25T16:22:34.227 回答
0

当我通过一个超级简单的测试使用 Highland.js 时,Mocha 毫无问题地捕获了失败的断言:

var _ = require("highland");
var fs = require("fs");
var assert = require("assert");

describe("test", function () {
    it("test", function (done) {
        var s = _([1, 2, 3, 4]);
        s.pull(function (err, result) {
            console.log(result);
            assert(false);
            done();
        });
    });
});

这表明您的示例中的问题不是 Mocha,也不是 Highland.js。如果articleLinkStream对象(或articleSream; 它似乎从片段更改为片段)是自定义代码,那么可能该代码有错误并且实际上会吞下异常而不是让它们向上移动堆栈。

于 2014-11-07T23:47:54.450 回答