AngularJSサービスを作成してあり、それを単体テストしたいと思います。
angular.module('myServiceProvider', ['fooServiceProvider', 'barServiceProvider']).
factory('myService', function ($http, fooService, barService) {
this.something = function() {
// Do something with the injected services
};
return this;
});
私のapp.jsファイルにはこれらが登録されています:
angular
.module('myApp', ['fooServiceProvider','barServiceProvider','myServiceProvider']
)
私はDIがそのように機能していることをテストできます:
describe("Using the DI framework", function() {
beforeEach(module('fooServiceProvider'));
beforeEach(module('barServiceProvider'));
beforeEach(module('myServiceProvder'));
var service;
beforeEach(inject(function(fooService, barService, myService) {
service=myService;
}));
it("can be instantiated", function() {
expect(service).not.toBeNull();
});
});
これは、サービスがDIフレームワークで作成できることを証明しましたが、次に、サービスの単体テストを行います。つまり、注入されたオブジェクトをモックアウトします。
これを行うにはどうすればよいですか?
私はモックオブジェクトをモジュールに入れようとしました。
beforeEach(module(mockNavigationService));
サービス定義を次のように書き換えます。
function MyService(http, fooService, barService) {
this.somthing = function() {
// Do something with the injected services
};
});
angular.module('myServiceProvider', ['fooServiceProvider', 'barServiceProvider']).
factory('myService', function ($http, fooService, barService) { return new MyService($http, fooService, barService); })
しかし、後者は、DIによって作成されるサービスをすべて停止するようです。
ユニットテストのために注入されたサービスをどのように模擬できるか知っていますか?
ありがとう
デビッド
$provide
を使用して、サービスにモックを挿入できます。
GetSomethingというメソッドを持つ依存関係を持つ次のサービスがある場合:
angular.module('myModule', [])
.factory('myService', function (myDependency) {
return {
useDependency: function () {
return myDependency.getSomething();
}
};
});
次のように、myDependencyのモックバージョンを挿入できます。
describe('Service: myService', function () {
var mockDependency;
beforeEach(module('myModule'));
beforeEach(function () {
mockDependency = {
getSomething: function () {
return 'mockReturnValue';
}
};
module(function ($provide) {
$provide.value('myDependency', mockDependency);
});
});
it('should return value from mock dependency', inject(function (myService) {
expect(myService.useDependency()).toBe('mockReturnValue');
}));
});
$provide.value
を呼び出すため、実際にmyDependencyをどこにでも明示的に注入する必要はありません。 myServiceの注入中に内部で発生します。ここでmockDependencyを設定すると、同じくらい簡単にスパイになる可能性があります。
loyalBrown のおかげで その素晴らしいビデオ へのリンクができました。
私の見方では、サービス自体をモックする必要はありません。サービスの機能を単純にモックします。そうすれば、アプリ全体で実行するように、angularに実際のサービスを注入させることができます。次に、JasmineのspyOn
関数を使用して、必要に応じてサービスの関数をモックします。
サービス自体が関数であり、spyOn
を使用できるオブジェクトではない場合、別の方法があります。私はこれをする必要があり、私にとってはかなりうまくいく何かを見つけました。 関数であるAngularサービスをどのようにモックしますか? を参照してください。
John Galambos 'answer に加えて、サービスの特定のメソッドをモックアウトするだけの場合は、次のようにできます。
describe('Service: myService', function () {
var mockDependency;
beforeEach(module('myModule'));
beforeEach(module(function ($provide, myDependencyProvider) {
// Get an instance of the real service, then modify specific functions
mockDependency = myDependencyProvider.$get();
mockDependency.getSomething = function() { return 'mockReturnValue'; };
$provide.value('myDependency', mockDependency);
});
it('should return value from mock dependency', inject(function (myService) {
expect(myService.useDependency()).toBe('mockReturnValue');
}));
});
AngularおよびJasmineでモックの依存関係を簡単にする別のオプションは、QuickMockを使用することです。 GitHubにあり、再利用可能な方法でシンプルなモックを作成できます。以下のリンクからGitHubからクローンを作成できます。 READMEは自明ですが、将来的に他の人にも役立つかもしれません。
https://github.com/tennisgent/QuickMock
describe('NotificationService', function () {
var notificationService;
beforeEach(function(){
notificationService = QuickMock({
providerName: 'NotificationService', // the provider we wish to test
moduleName: 'QuickMockDemo', // the module that contains our provider
mockModules: ['QuickMockDemoMocks'] // module(s) that contains mocks for our provider's dependencies
});
});
....
上記のすべてのボイラープレートを自動的に管理するため、すべてのテストでそのモックインジェクションコードをすべて記述する必要はありません。それが役に立てば幸いです。
コントローラが次のような依存関係を取り込むように書かれている場合:
app.controller("SomeController", ["$scope", "someDependency", function ($scope, someDependency) {
someDependency.someFunction();
}]);
次のようなジャスミンテストで偽のsomeDependency
を作成できます。
describe("Some Controller", function () {
beforeEach(module("app"));
it("should call someMethod on someDependency", inject(function ($rootScope, $controller) {
// make a fake SomeDependency object
var someDependency = {
someFunction: function () { }
};
spyOn(someDependency, "someFunction");
// this instantiates SomeController, using the passed in object to resolve dependencies
controller("SomeController", { $scope: scope, someDependency: someDependency });
expect(someDependency.someFunction).toHaveBeenCalled();
}));
});
私は最近、AngularJSでの模擬テストを簡単にするngImprovedTestingをリリースしました。
FooServiceおよびbarServiceの依存関係をモックアウトして「myService」(「myApp」モジュールから)をテストするには、Jasmineテストで以下を実行できます。
beforeEach(ModuleBuilder
.forModule('myApp')
.serviceWithMocksFor('myService', 'fooService', 'barService')
.build());
NgImprovedTestingの詳細については、紹介ブログ投稿をご覧ください: http://blog.jdriven.com/2014/07/ng-improved-testing-mock-testing-for-angularjs-made-easy/ =
私はこれが古い質問であることを知っていますが、別の簡単な方法があります、あなたはモックを作成し、1つの関数で注入されたオリジナルを無効にすることができます、それはすべてのメソッドでspyOnを使用して行うことができます以下のコードを参照してください。
var mockInjectedProvider;
beforeEach(function () {
module('myModule');
});
beforeEach(inject(function (_injected_) {
mockInjectedProvider = mock(_injected_);
});
beforeEach(inject(function (_base_) {
baseProvider = _base_;
}));
it("injectedProvider should be mocked", function () {
mockInjectedProvider.myFunc.andReturn('testvalue');
var resultFromMockedProvider = baseProvider.executeMyFuncFromInjected();
expect(resultFromMockedProvider).toEqual('testvalue');
});
//mock all service methods
function mock(angularServiceToMock) {
for (var i = 0; i < Object.getOwnPropertyNames(angularServiceToMock).length; i++) {
spyOn(angularServiceToMock,Object.getOwnPropertyNames(angularServiceToMock)[i]);
}
return angularServiceToMock;
}