返回承诺的ember控制器中的单元测试操作

时间:2014-07-16 04:44:24

标签: javascript unit-testing ember.js ember-qunit ic-ajax

我有一个执行异步操作的控制器,我想测试一下:

/*globals Ember, momnent*/
import { raw as icAjaxRaw } from 'ic-ajax';

//...

    actions: {
        foo: function() {
            var req = icAjaxRaw({
                type: 'POST',
                url: ApiUtils.apiUrl+'/dofoo',
                processData: false,
            });

            return req.then(
                function resolve(result) {
                    console.log(result.response);
                    this.set('fooLastDoneAt', moment());
                }.bind(this)
            );
        },

......并且在测试中:

test('actions.foo', function() {
    expect(2);
    var ctrl = this.subject();
    var model = {
        fooLastDoneAt: moment().add(-10, 'days'),
    };
    ctrl.set('model', model);
    ok(ctrl.get('fooLastDoneAt').isBefore(moment().add(-1, 'days')), true, 'initial');
    ctrl.send('foo');
    ok(ctrl.get('fooLastDoneAt').isBefore(moment().add(-1, 'days')), false, 'updated date');
});

然而,在另一个不相关的测试案例中,这不可避免地导致错误抛出:

"Uncaught Error: Assertion Failed: calling set on destroyed object"[

必须发生,因为在此测试用例完成后执行了this.set('fooLastDoneAt', moment());,并且测试运行器为此模块完成了teardown,然后继续执行下一个模块;行动仍在执行中。

在继续进行单元测试的下一步之前,我有没有办法等待动作异步完成?


@ kingpin2k建议this solution, 将promise deferred对象传入操作的位置。 但是,在我的应用程序中,应用程序本身永远不会这样做, 如果我需要修改我的应用程序源代码,这似乎是一个基本问题 只是为了它可以测试 - 特别是因为它增加了复杂性。

还有其他方法可以让测试执行等待操作完成吗?

1 个答案:

答案 0 :(得分:1)

我会选择QUnit start() stop()个功能。

以下是从QUnit文档中使用的示例:

QUnit.test( "a test", function( assert ) {
  QUnit.stop();
  asyncOp();
  setTimeout(function() {
    assert.equals( asyncOp.result, "someExpectedValue" );
    QUnit.start();
  }, 150 );
});

同样ember-qunit库通过then覆盖了此内容。

以下是ember-qunit

的示例
test('actions.foo', function() {
    expect(2);
    var ctrl = this.subject();
    var model = {
        fooLastDoneAt: moment().add(-10, 'days'),
    };
    ctrl.set('model', model);
    ok(ctrl.get('fooLastDoneAt').isBefore(moment().add(-1, 'days')), true, 'initial');
    ctrl.send('foo').then(function(){
      ok(ctrl.get('fooLastDoneAt').isBefore(moment().add(-1, 'days')), false, 'updated date');
    });
});

我没有测试代码,所以我希望它能解决你的问题