如何模拟在 AngularJS Jasmine 单元测试中返回承诺的服务? [英] How do I mock a service that returns promise in AngularJS Jasmine unit test?

查看:28
本文介绍了如何模拟在 AngularJS Jasmine 单元测试中返回承诺的服务?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有使用 myOtherServicemyService,它进行远程调用,返回承诺:

I have myService that uses myOtherService, which makes a remote call, returning promise:

angular.module('app.myService', ['app.myOtherService'])
  .factory('myService', [
    myOtherService,
    function(myOtherService) {
      function makeRemoteCall() {
        return myOtherService.makeRemoteCallReturningPromise();
      }

      return {
        makeRemoteCall: makeRemoteCall
      };      
    }
  ])

要对 myService 进行单元测试,我需要模拟 myOtherService,使其 makeRemoteCallReturningPromise 方法返回一个承诺.我是这样做的:

To make a unit test for myService I need to mock myOtherService, such that its makeRemoteCallReturningPromise method returns a promise. This is how I do it:

describe('Testing remote call returning promise', function() {
  var myService;
  var myOtherServiceMock = {};

  beforeEach(module('app.myService'));

  // I have to inject mock when calling module(),
  // and module() should come before any inject()
  beforeEach(module(function ($provide) {
    $provide.value('myOtherService', myOtherServiceMock);
  }));

  // However, in order to properly construct my mock
  // I need $q, which can give me a promise
  beforeEach(inject(function(_myService_, $q){
    myService = _myService_;
    myOtherServiceMock = {
      makeRemoteCallReturningPromise: function() {
        var deferred = $q.defer();

        deferred.resolve('Remote call result');

        return deferred.promise;
      }    
    };
  }

  // Here the value of myOtherServiceMock is not
  // updated, and it is still {}
  it('can do remote call', inject(function() {
    myService.makeRemoteCall() // Error: makeRemoteCall() is not defined on {}
      .then(function() {
        console.log('Success');
      });    
  }));  

从上面可以看出,我的模拟的定义取决于 $q,我必须使用 inject() 加载它.此外,注入模拟应该发生在 module() 中,它应该在 inject() 之前出现.但是,一旦我更改它,模拟的值就不会更新.

As you can see from the above, the definition of my mock depends on $q, which I have to load using inject(). Furthermore, injecting the mock should be happening in module(), which should be coming before inject(). However, the value for the mock is not updated once I change it.

这样做的正确方法是什么?

What is the proper way to do this?

推荐答案

我不知道为什么你的方法不起作用,但我通常使用 spyOn 函数来完成.像这样:

I'm not sure why the way you did it doesn't work, but I usually do it with the spyOn function. Something like this:

describe('Testing remote call returning promise', function() {
  var myService;

  beforeEach(module('app.myService'));

  beforeEach(inject( function(_myService_, myOtherService, $q){
    myService = _myService_;
    spyOn(myOtherService, "makeRemoteCallReturningPromise").and.callFake(function() {
        var deferred = $q.defer();
        deferred.resolve('Remote call result');
        return deferred.promise;
    });
  }

  it('can do remote call', inject(function() {
    myService.makeRemoteCall()
      .then(function() {
        console.log('Success');
      });    
  }));

还请记住,您需要调用 $digest 来调用 then 函数.请参阅$q 文档测试部分.

Also remember that you will need to make a $digest call for the then function to be called. See the Testing section of the $q documentation.

------编辑------

仔细查看您正在做的事情后,我想我在您的代码中看到了问题.在 beforeEach 中,您将 myOtherServiceMock 设置为一个全新的对象.$provide 永远不会看到这个引用.您只需要更新现有的参考:

After looking closer at what you're doing, I think I see the problem in your code. In the beforeEach, you're setting myOtherServiceMock to a whole new object. The $provide will never see this reference. You just need to update the existing reference:

beforeEach(inject( function(_myService_, $q){
    myService = _myService_;
    myOtherServiceMock.makeRemoteCallReturningPromise = function() {
        var deferred = $q.defer();
        deferred.resolve('Remote call result');
        return deferred.promise;   
    };
  }

这篇关于如何模拟在 AngularJS Jasmine 单元测试中返回承诺的服务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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