![](/img/trans.png)
[英]Angular Karma/Jasmine testing: How to mock a service in controller with promises?
[英]How to mock AngularJS promises using Jasmine / Karma?
这是我的控制器:
angular.module("AuthenticationApp", ["BaseApp"])
.controller("AuthCtrl", ["$http", "BaseService", function($http, BaseService) {
var self = this;
BaseService.fetch.stuffs()
.then(function(data) {
self.stuffs = data;
});
}]);
这是我的BaseService
(我需要模拟的工厂):
angular.module("BaseApp", ["ngRoute"])
.factory("BaseService", ["$http", "$q", function($http, $q) {
var self = this;
self.fetch = {
stuffs: function() {
return $http.get("/api/stuffs/")
.then(function(response) {
return response.data;
});
}
};
return self;
}]);
我不知道从哪里开始。 我试过的是:
describe('Controller: AuthCtrl', function() {
var ctrl, mockBaseService;
beforeEach(function() {
mockBaseService = {
stuffs: 'test',
fetch: {
stuffs: function() {
return {
then: function() {
return {stuffs: "stuffs"};
},
}
},
},
};
spyOn(mockBaseService.fetch, 'stuffs');
module('BaseApp', function($provide) {
$provide.value('BaseService', mockBaseService);
});
module('AuthenticationApp');
inject(function($controller) {
ctrl = $controller('AuthCtrl', {
});
});
});
it('BaseService.fetch.stuffs should be called on page load', function() {
expect(mockBaseService.fetch.stuffs).toHaveBeenCalled();
expect(ctrl.stuffs).toBe({stuffs: "stuffs"});
});
});
但是,当我测试此代码时,出现错误消息:
TypeError: Cannot read property 'then' of undefined
at new <anonymous> (/home/user/Documents/ebdjango/ebdjangoapp/static/js/home.js:15:11)
home.js
第15行是控制器中的以下行:
return $http.get("/api/stuffs/")
.then(function(response) { // line 15
return response.data;
});
如何正确模拟呢?
编辑:我阅读了注释中提到的文档,然后将mockBaseService
更改为:
describe('Controller: AuthCtrl', function() {
var ctrl, mockBaseService;
beforeEach(function() {
// create promise
var deferred = $q.defer();
var promise = deferred.promise;
// make promise.then return {stuffs: "stuffs"}
promise.then(function(value) { return {stuffs: "stuffs" }; });
mockBaseService = {
stuffs: 'stuffs',
fetch: {
stuffs: function() {
return promise;
},
},
};
spyOn(mockBaseService.fetch, 'stuffs');
module('BaseApp', function($provide) {
$provide.value('BaseService', mockBaseService);
});
module('AuthenticationApp');
inject(function($controller) {
ctrl = $controller('AuthCtrl', {
});
});
});
it('BaseService.fetch.stuffs should be called on page load', inject(function($rootScope) {
deferred.resolve('test');
$rootScope.$apply();
expect(mockBaseService.fetch.stuffs).toHaveBeenCalled();
expect(ctrl.stuffs).toBe({stuffs: "stuffs"});
}));
});
但这会返回ReferenceError: $q is not defined
错误。 我尝试像这样注入_$q_
:
beforeEach(inject(function(_$q_) {
$q = _$q_;
// ... everything else goes here... //
但是然后我收到一条错误消息,提示Error: Injector already created, can not register a module!
。 此处: 喷油器已创建。 无法注册一个模块,它说如果我们在inject($someDependency)
之前执行module('someApp')
,则可以解决此问题。 但是我做不到
module('BaseApp', function($provide) {
$provide.value('BaseService', mockBaseService);
});
在注入_$q_
之前,因为$q
用于mockBaseService
。 我从这里去哪里?
嘲笑我一直都在做
1) spyOn(service,'method').andCallFake( $q.when( Fixture.data() ) )
不要创建那个模拟数据库服务,我之前已经做过了,而且很多事情都没有写。也可以使用以拦截$ http的方式构建的AngularJS。
2) $httpBackend.when('GET', '/url').respond(Fixture.data())
我绝对喜欢1),因为我喜欢在进行测试时将自己隔离在特定的层中。 我想这取决于口味
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.