Injecting dependent services when unit testing AngularJS services

后端 未结 5 1480
隐瞒了意图╮
隐瞒了意图╮ 2020-12-08 00:06

I\'m testing service A, but service A depends on service B (i.e. service B is injected into service A).

I\'ve seen this question but my case is a bit different becau

相关标签:
5条回答
  • 2020-12-08 00:46

    I find the simplest method is just to inject service B and mock it. e.g. Service car depends on service Engine. Now we need to mock Engine when testing Car:

    describe('Testing a car', function() {
          var testEngine;
    
      beforeEach(module('plunker'));
      beforeEach(inject(function(engine){
        testEngine = engine;
      }));
    
      it('should drive slow with a slow engine', inject(function(car) {
        spyOn(testEngine, 'speed').andReturn('slow');
        expect(car.drive()).toEqual('Driving: slow');
      }));
    });
    

    Reference: https://github.com/angular/angular.js/issues/1635

    0 讨论(0)
  • 2020-12-08 00:47

    This is what worked for me. The key is defining a real module to be mocked. Calling angular.mock.module makes the real module mockable and allows things to be connected.

        beforeEach( ->
            @weather_service_url = '/weather_service_url'
            @weather_provider_url = '/weather_provider_url'
            @weather_provider_image = "test.jpeg"
            @http_ret = 'http_works'
            module = angular.module('mockModule',[])
            module.value('weather_service_url', @weather_service_url)
            module.value('weather_provider_url', @weather_provider_url)
            module.value('weather_provider_image', @weather_provider_image)
            module.service('weather_bug_service', services.WeatherBugService)
    
            angular.mock.module('mockModule')
    
            inject( ($httpBackend,weather_bug_service) =>
                @$httpBackend = $httpBackend
                @$httpBackend.when('GET', @weather_service_url).respond(@http_ret)
                @subject = weather_bug_service
            )
        )
    
    0 讨论(0)
  • 2020-12-08 00:55

    The Valentyn solution worked for me, but there is another alternative.

    beforeEach(function () {
    
        angular.mock.module("moduleThatContainsServiceA", function ($provide) {
                    $provide.value('B', ...);
                });
    });
    

    Then when AngularJS service A request the Service B by Dependency Injection, your mock of Service B will be provided instead of the Service B from moduleThatContainsServiceA.

    This way you don't need to create an additional angular module just to mock a Service.

    0 讨论(0)
  • 2020-12-08 00:59

    I was doing this in CoffeeScript and found an extra gotcha. (Also, I found the code on this page to be confusingly terse.) Here's a complete working example:

    describe 'serviceA', ->
       mockServiceB = {}
    
       beforeEach module 'myApp' # (or just 'myApp.services')
    
       beforeEach ->
          angular.mock.module ($provide) ->
             $provide.value 'serviceB', mockServiceB
             null
    
       serviceA = null
       beforeEach inject ($injector) ->
          serviceA = $injector.get 'serviceA'
    
       it 'should work', ->
          expect( true ).toBe( true )
          #serviceA.doStuff()
    

    Without explicitly returning null after $provide.value, I kept getting Error: Argument 'fn' is not a function, got Object. I found the answer in this Google Groups thread.

    0 讨论(0)
  • 2020-12-08 01:00

    Actually in AngularJS Dependency Injection uses the 'last wins' rule. So you can define your service in your test just after including your module and dependencies, and then when service A that you're testing will request service B using DI, AngularJS will give mocked version of service B.

    This is often is done by defining new module like MyAppMocks, putting mocked services/values there and then just adding this module as dependency.

    Kind of (schematically):

    beforeEach(function() {
      angular.module('MyAppMocks',[]).service('B', ...));
      angular.module('Test',['MyApp','MyAppMocks']);
      ...
    
    0 讨论(0)
提交回复
热议问题