2013-10-10 83 views
38

我正在嘲笑AngularJS單元測試的服務。我使用的是$provide服務與嘲笑了一個(這是可用plunker script),以取代「真實」服務:

describe('My Controller', function() { 

    var $scope; 
    var $provide; 

    beforeEach(angular.mock.module('myApp')); 

    beforeEach(angular.mock.module(function (_$provide_) { 

     $provide = _$provide_; 

    })); 

    beforeEach(angular.mock.inject(function($rootScope, $controller, $q){ 

     var mockMyService = { 
      getAll : function() { 
       var deferred = $q.defer(); 
       deferred.resolve([ 
      { itemText: "Foo" }, 
      { itemText: "Bar" } 
       ]); 

       return deferred.promise; 
      } 
     }; 

     $provide.value('myService', mockMyService); 

     $scope = $rootScope.$new(); 

     $controller('MyCtrl', { $scope: $scope }); 

     $rootScope.$apply(); 

    })); 

    it('Has two items defined', function() { 
     expect($scope.items.length).toEqual(2); 
    }); 
}); 

這一切正常。但是,我不喜歡我使用angular.mock.module函數僅僅提供$provide服務的事實,該服務隨後在以下angular.mock.inject函數中使用。但是,如果直接將$provide作爲參數添加到angular.mock.inject函數中,則會出現「未知提供者」錯誤。

在我看來,我可以把所有模擬代碼放在angular.mock.module函數中。但後來我有一個類似的問題,$q參考,我需要我的模擬服務必須返回一個承諾。

換句話說,如果我將一個$q參數添加到angular.mock.module函數,那麼我也會得到一個'unknown provider'錯誤。

有沒有辦法簡化這個?很顯然,我有些作品,但不知怎的,它感覺不太對勁。我覺得我對inject函數中爲什麼有些提供程序可用以及module函數中可用的其他提供程序不瞭解。

回答

53

您不能在inject函數中使用$provide,因爲前者的註冊提供程序供後者使用。請看:

describe('...', function() { 
    beforeEach(function() { 
     module(function($provide) { 
      $provide.constant('someValue', 'foobar'); 
     }); 

     inject(function(someValue) { 
      var value = someValue; // will be 'foobar'; 
     }); 
    }); 
}); 

你可以儘管編寫測試是這樣的:

describe('...', function() { 
    var serviceMock; 

    beforeEach(function() { 
     serviceMock = { 
      someMethod: function() { ... } 
     }; 

     module(function($provide) { 
      $provide.value('service', serviceMock); 
     }); 

     inject(function(service) { 
      ...       
     }); 
    }); 
}); 

事實上,你甚至不需要與$provide注射之前實現嘲笑服務:

beforeEach(function() { 
    serviceMock = {}; 

    module(function($provide) { 
     $provide.value('service', serviceMock); 
    }); 

    inject(function(service) { 
     ...       
    }); 
}); 

it('tests something', function() { 
    // Arrange 
    serviceMock.someMethod = function() { ... } 

    // Act 
    // does something 

    // Assert 
    expect(...).toBe(...); 
}); 

這裏是一個Plunker script說明主要是上述。

+0

這是非常好的,它的工作原理...只要你不使用諾言。這裏是一個顯示我原來的例子plunk:http://plnkr.co/edit/1Gbr1N?p=preview 這裏是一個叉你用建議的技術更新:http://plnkr.co/edit/ptAWcb?p =預覽 模擬服務沒有被分配;它看起來好像有些事情正在干擾時機。 – Holf

+0

我想知道爲什麼我無法從'模塊'功能中獲得'$ q'庫?如果可以的話,那麼我就有我需要的一切來在那裏創建模擬服務。 – Holf

+7

@Holf您可以使用承諾,但您需要首先移動一些東西。看看這個更新的[Plunker腳本](http://plnkr.co/edit/Fi1SQq)。 –

11

這爲我工作,當我不得不換用它和$q看起來挺乾淨的一個服務:

var _ServiceToTest_; 
beforeEach(function() { 
    module('module.being.tested'); 
    module(function ($provide) { 
     $provide.factory('ServiceToMock', function ($q, $rootScope) { 
      var service = ...; 
      // use $q et al to heart's content 
      return service; 
     }); 
    }); 
    inject(function (_ServiceToTest_) { 
     ServiceToTest = _ServiceToTest_; 
    }); 
}); 

it('...', function() { /* code using ServiceToTest */ }); 

訣竅是使用$provide.factory而不是$provide.value

相關問題