Angularjs - 如何使用模拟正确替换服务依赖项

问题描述 投票:0回答:3

我正在使用 yeoman 生成器创建的应用程序,并在 karma 中进行测试。

我的每项服务都有可重用的模拟对象。 我如何正确地用模拟替换特定的服务依赖性,这样我就可以使用 jasmine 来监视方法

到目前为止我已经这样做了:

我的服务:

angular.module('ql')
  .service('loginService', ['$http','API','authService', function ($http, API, authService) {
    return {
      //service implementation
    }]);

authService 的模拟:

'use strict';
//lets mock http auth  service, so it would be spied upon.
ql.mock.$authServiceMockProvider = function() {
  this.$get = function() {
    var $service = {
      loginConfirmed: function() { }
    };
    return $service;
  };
};

//and register it.
angular.module('qlMock').provider({
  $authServiceMock: ql.mock.$authServiceMockProvider
});

我的测试:

'use strict';

describe('When i call login method()', function () {

  // load the service's module
  beforeEach(module('ql'));
  beforeEach(angular.mock.module('qlMock'));

  // instantiate service
  var loginService,
  authService,
  $httpBackend;
  beforeEach(function() {
    // replace auth service with a mock.
    // this seems kind of dirty... is there a bettery way? 
    module(function($provide, $injector){
      authService = $injector.get('$authServiceMockProvider').$get();
      $provide.value('authService', authService);
    });

    //actually get the loginService
    /*jshint camelcase: false */
    inject(function(_loginService_, _$httpBackend_) {
      loginService = _loginService_;
      $httpBackend =_$httpBackend_;
    });

    //http auth module method, that should be call only on success scenarios
    spyOn(authService, 'loginConfirmed').andCallThrough();
  });
  it('it should do something', function () {
  //actual test logic
  });
});

我不喜欢的是这句话:

authService = $injector.get('$authServiceMockProvider').$get();

我想简单地以某种方式获取 authServiceMock (无需获取提供程序,并调用 et 方法),然后将其注入到 loginService 中。

我知道我可以简单地调用我的 $authServiceMock authService,并将其作为模拟提供,这样它总是会覆盖我的默认实现,但我不想这样做。

unit-testing angularjs karma-runner
3个回答
15
投票

我知道这已经晚了,但也许它会对偶然看到这篇文章的人有所帮助。

使用 Angular 的 $provide 服务在 Jasmine 中模拟服务非常简单。技巧是在注入服务之前使用 $provide 替换服务实现。

例如,假设我们正在测试一项服务,该服务利用 $location 服务来获取有关当前 URL 的信息。

// load the service's module under test
beforeEach(module('myExampleModule'));

// mock out $location with a fake one
beforeEach(
  module(function ($provide) {
    //create mock impl
    var mockLocation = {
      path: function () {
        return '/somewhere';
      }
    };

    // use $provide to swap the real $location with our mock
    $provide.value('$location', mockLocation);
  })
);

var $location;
// inject dependencies ($location will be our mocked $location)
beforeEach(inject(function (_$location_) {
  $location = _$location_;
}));

it('should return mock url', function () {
  var path = $location.path();

  //Assert that $location.path() returns '/somewhere'
  expect(path).toBe('/somewhere');
});

0
投票

我想我会简单地使用角度服务装饰器来模拟或完全替换您的测试服务。 这是一个例子


0
投票

我从未对服务中的服务进行过单元测试,至少还没有,但我们的身份验证/登录内容很快就会推出。

当您对 loginService 进行单元测试时,您只对服务与 AuthService 提供的数据交互的方式感兴趣,而不是对 AuthService 是否正常工作感兴趣。这就是您在模拟中设置的。

我认为这将是我的方法:(在家长中描述)

  var   
     loginService, 
     authService
     AUTH_DATA
  ;

  beforeEach(function() {
     module('ql');
     // I am assuming this is the global app module so both services live here? If not include this module as well
  });


   beforeEach(inject(function (_authService_, _loginService_) {
      authService = _authService_;
      loginService = _loginService_;
      //Now with the spy setup you intercept the calls to the service and you choose what data to return, based on the unit test. Now your LoginService can simply resond to the data it is give from the login service
    }));

  it('it should do something', function () {
     spyOn(authService, 'loginConfirmed').andReturn(AUTH_DATA);
     loginService.confirmLogin(); //Dont know your actual API but a contrived guess
     expect('something to happen in loginservice when AUTH_DATA is returned').toBe('Something else')
   });
© www.soinside.com 2019 - 2024. All rights reserved.