Angularjs 中基于单元测试的代码 [英] Unit-test promise-based code in Angularjs

查看:22
本文介绍了Angularjs 中基于单元测试的代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很难在 Angularjs 中测试基于 Promise 的代码.

I'm having hard times trying to test promise-based code in Angularjs.

我的控制器中有以下代码:

I have the following code in my controller:

    $scope.markAsDone = function(taskId) {
        tasksService.removeAndGetNext(taskId).then(function(nextTask) {
            goTo(nextTask);
        })
    };

    function goTo(nextTask) {
        $location.path(...);
    }

我想对以下情况进行单元测试:

I'd like to unit-test the following cases:

  • markAsDone 被调用时,它应该调用 tasksService.removeAndGetNext
  • tasksService.removeAndGetNext 完成后,它应该改变位置(调用 goTo)
  • when markAsDone is called it should call tasksService.removeAndGetNext
  • when tasksService.removeAndGetNext is done it should change location (invoke goTo)

在我看来,单独测试这两种情况没有简单的方法.

It seems to me that there is no easy way to test those two cases separately.

我为测试第一个所做的工作是:

What I did to test the first one was:

var noopPromise= {then: function() {}}
spyOn(tasksService, 'removeAndGetNext').andReturn(noopPromise);

现在为了测试第二种情况,我需要创建另一个总是resolved的虚假承诺.这一切都很乏味,而且有很多样板代码.

Now to test the second case I need to create another fake promise that would be always resolved. It's all quite tedious and it's a lot of boilerplate code.

有没有其他方法可以测试这些东西?还是我的设计有味道?

Is there any other way to test such things? Or does my design smell?

推荐答案

您仍然需要模拟服务并返回承诺,但您应该改用真实的承诺,因此您不需要实现其功能.使用 beforeEach 来创建已经实现的承诺,如果你需要它总是被解决的话,可以模拟服务.

You will still need to mock the services and return a promise, but you should use real promises instead, so you don't need to implement its functionality. Use beforeEach to create the already fulfilled promise and mock the service if you need it to ALWAYS be resolved.

var $rootScope;

beforeEach(inject(function(_$rootScope_, $q) {
  $rootScope = _$rootScope_;

  var deferred = $q.defer();
  deferred.resolve('somevalue'); //  always resolved, you can do it from your spec

  // jasmine 2.0
  spyOn(tasksService, 'removeAndGetNext').and.returnValue(deferred.promise); 

  // jasmine 1.3
  //spyOn(tasksService, 'removeAndGetNext').andReturn(deferred.promise); 

}));

如果您更愿意在每个 it 块中使用不同的值解析它,那么您只需将延迟暴露给局部变量并在规范中解析它.

If you'd rather prefer to resolve it in each it block with a different value, then you just expose the deferred to a local variable and resolve it in the spec.

当然,您可以保持测试原样,但这里有一些非常简单的规范来向您展示它是如何工作的.

Of course, you would keep your tests as they are, but here is some really simple spec to show you how it would work.

it ('should test receive the fulfilled promise', function() {
  var result;

  tasksService.removeAndGetNext().then(function(returnFromPromise) {
    result = returnFromPromise;
  });

  $rootScope.$apply(); // promises are resolved/dispatched only on next $digest cycle
  expect(result).toBe('somevalue');
});

这篇关于Angularjs 中基于单元测试的代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆