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 에게 감사드립니다 .
답변
제가보기에는 서비스 자체를 조롱 할 필요가 없습니다. 서비스의 기능을 조롱하기 만하면됩니다. 이렇게하면 앱 전체 에서처럼 실제 서비스를 각도 주입 할 수 있습니다. 그런 다음 Jasmine의 spyOn
기능을 사용하여 필요에 따라 서비스의 기능을 모의합니다 .
이제 서비스 자체가 함수이고 spyOn
함께 사용할 수있는 객체가 아니라면 다른 방법이 있습니다. 이 작업을 수행해야했고 저에게 잘 맞는 것을 찾았습니다. 함수 인 Angular 서비스를 어떻게 모의합니까?를 참조하십시오 .
답변
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
});
});
....
위에서 언급 한 모든 상용구를 자동으로 관리하므로 모든 테스트에서 모의 주입 코드를 모두 작성할 필요가 없습니다. 도움이되기를 바랍니다.
답변
John Galambos의 답변 외에도 서비스의 특정 방법을 조롱하고 싶다면 다음과 같이 할 수 있습니다.
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');
}));
});
답변
컨트롤러가 다음과 같은 종속성을 갖도록 작성된 경우 :
app.controller("SomeController", ["$scope", "someDependency", function ($scope, someDependency) {
someDependency.someFunction();
}]);
그런 다음 다음 someDependency
과 같이 Jasmine 테스트에서 가짜 를 만들 수 있습니다 .
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/
답변
나는 이것이 오래된 질문이라는 것을 알고 있지만 또 다른 쉬운 방법이 있습니다. 모의를 만들고 하나의 기능에 주입 된 원본을 비활성화 할 수 있습니다. 모든 방법에서 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;
}