我在角度服务中使用$ resource。 我想使用我自己的基于$ cacheFactory的自定义缓存,而不是内置的$ http缓存,这样我就可以在响应从我的REST服务返回时操作缓存。
我在单元测试中模拟$ cacheFactory很困难,有人可以帮我定义正确的模拟和设置我的测试吗?
以下是我要测试的代码的简化版本。请注意,我告诉我的角度应用使用我的自定义缓存'DefaultCache'
而不是$http
中可能使用的默认myApp.run()
缓存。 (我理解这是替换所有$ resource服务的默认缓存的方法。)
var myServices = angular.module('myServices', ['ngResource']);
var myApp = angular.module('myApp', [
'myServices'
]);
myApp.run([
'$http',
'$cacheFactory',
function ($http, $cacheFactory) {
// Replace default $http cache with one we can control
$http.defaults.cache = $cacheFactory('defaultCache');
}]);
myServices.factory('MyService', [
'$resource',
'$cacheFactory',
function($resource, $cacheFactory) {
var cache = $cacheFactory.get('defaultCache');
function doSomething(data) {
var cached = cache.get('akey');
return angular.fromJson(data);
}
return {
things: $resource('/api/things/:id', { id: '@id' }, {
query: {
method: 'GET',
isArray: true,
cache: true,
transformResponse: function(data) {
return doSomething(data);
},
},
})
}
}]);
这是我的测试设置。 (注意:提供的mockCacheFactory返回一个对象):
///<reference path="~/Scripts/jasminejs/jasmine.js"/>
///<reference path="../../Web/Scripts/angularjs/angular.js"/>
///<reference path="../../Web/Scripts/angularjs/angular-mocks.js"/>
///<reference path="../../Web/Scripts/angularjs/angular-resource.js"/>
describe("MyServiceSpec", function () {
beforeEach(module('myServices'));
describe('GivenThingsResource', function () {
var $httpBackend, MyService, mockCacheFactory;
beforeEach(module(function ($provide) {
mockCacheFactory = {
get: function (cacheName) {
return {
get: function (key) { },
put: function (key, value) { },
};
},
};
$provide.value('$cacheFactory', mockCacheFactory);
}));
beforeEach(inject(function (_$httpBackend_, _MyService_) {
$httpBackend = _$httpBackend_;
MyService = _MyService_;
spyOn(mockCacheFactory, 'get').andCallThrough();
}));
it("WhenQuery_ThenReturnsData", function () {
$httpBackend.expectGET('/api/things').respond(JSON.stringify({ Things: [{ Id: '1' }, { Id: '2' }] }));
var result = MyService.things.query();
$httpBackend.flush();
expect(result).toEqualData({ Things: [{ Id: '1' }, { Id: '2' }] });
});
});
});
我看到的问题是:当测试运行时,我得到了这两个错误:
TypeError: 'undefined' is not an object (evaluating '$httpBackend.expectGET') in http://localhost:35050/Tests.js (line 76)
TypeError: 'undefined' is not an object (evaluating '$httpBackend.expectGET')
at TestSpec.js: line 76
at jasmine.js: line 1064
at jasmine.js: line 2096
at jasmine.js: line 2086TypeError: '[object Object]' is not a function (evaluating '$cacheFactory('$http')')
TypeError: '[object Object]' is not a function (evaluating '$cacheFactory('$http')')
at angular.js: line 7527
at invoke ( angular.js: line 3966)
at angular.js: line 3808
at getService ( angular.js: line 3930)
at invoke ( angular.js: line 3957)
at angular.js: line 3808
at getService ( angular.js: line 3930)
at invoke ( angular.js: line 3957)
at angular.js: line 3808
at getService ( angular.js: line 3930)
at invoke ( angular.js: line 3957)
at workFn ( angular-mocks.js: line 2161)
at jasmine.js: line 1064
at jasmine.js: line 2096
at jasmine.js: line 2086
undefined
所以,我认为我的模拟是错误的,所以我将提供的mockCacheFactory
更改为一个函数,以便对$cacheFactory('$http')
的调用成功:
mockCacheFactory = function () {
return {
get: function (cacheName) {
return {
get: function (key) { },
put: function (key, value) { },
};
},
};
};
但我现在得到这些错误:
TypeError: 'undefined' is not a function (evaluating '$cacheFactory.get('defaultCache')')
TypeError: 'undefined' is not a function (evaluating '$cacheFactory.get('defaultCache')')
at TestSpec.js: line 25
at invoke ( angular.js: line 3966)
at angular.js: line 3808
at getService ( angular.js: line 3930)
at invoke ( angular.js: line 3957)
at workFn ( angular-mocks.js: line 2161)
at jasmine.js: line 1064
at jasmine.js: line 2096
at jasmine.js: line 2086
undefinedTypeError: 'undefined' is not an object (evaluating '$httpBackend.expectGET') in http://localhost:40529/Tests.js (line 78)
TypeError: 'undefined' is not an object (evaluating '$httpBackend.expectGET')
at TestSpec.js: line 78
at jasmine.js: line 1064
at jasmine.js: line 2096
at jasmine.js: line 2086
我真的不明白我的模拟中需要什么来满足使用我的模拟的代码。它似乎需要有一些javascript二元性,我不知道如何模仿我对mock的定义。
有谁知道我的模拟应该如何构建?或者我在这里还缺少什么?
答案 0 :(得分:4)
今天我在同样的问题上挣扎,并找到了一个不同的解决方案来完成这项工作。 (Angular 1.3.13)
外观$ cacheFactory有一个get方法,因此您可以检索cacheId的实例。 这将使您能够监视正确的缓存实例。
beforeEach(inject(function (_$cacheFactory_) {
mockCache = _$cacheFactory_.get('defaultCache');
}));
it('your test', function () {
spyOn(mockCache, 'get').andCallThrough();
....
expect(mockCache.get).toHaveBeenCalledWith('akey');
});
答案 1 :(得分:1)
对于后来遇到同样问题的人。
我发现无法构建适用于此代码的模拟。我甚至采用了$ cacheFactory(来自github)的实现,剥离了它的实现并尝试使用它作为模拟,将其插入测试中。那里也没有运气。
然而,我做了一个随机的帖子,暗示我可能应该创建一个自己的缓存服务(在我自己的服务中),这将使用$ cacheFactory创建一个缓存。然后,我可以将我的cachingservice注入我的资源(正常的服务),而不是直接使用$ cacheFactory。嘲笑缓存服务应该很简单。我做到了,现在很好。
我的新缓存服务:
myServices.factory('ServiceCachingService', [
'$cacheFactory',
function (
$cacheFactory
) {
return $cacheFactory('defaultCache');
}]);
新app.run():
myApp.run([
'$http',
'ServiceCachingService',
function ($http, ServiceCachingService) {
// Replace default $http cache with one we can control
$http.defaults.cache = ServiceCachingService;
}]);
我的新数据服务:
myServices.factory('MyService', [
'$resource',
'ServiceCachingService',
function($resource, ServiceCachingService) {
function doSomething(data) {
var cached = ServiceCachingService.get('akey');
return angular.fromJson(data);
}
return {
things: $resource('/api/things/:id', { id: '@id' }, {
query: {
method: 'GET',
isArray: true,
cache: true,
transformResponse: function(data) {
return doSomething(data);
},
},
})
}
}]);
然后是新的测试模拟:
mockCachingService = {
get: function (key) {},
put: function (key, value) { },
};
答案 2 :(得分:1)
以下代码将允许您在单元测试中模拟$ cacheFactory。 $ provide服务将允许服务依赖注入使用$ cacheFactory而不是默认的$ cacheFactory。
var cache, $cacheFactory; //used in your its
beforeEach(function(){
module(function ($provide) {
$cacheFactory = function(){};
$cacheFactory.get = function(){};
cache = {
removeAll: function (){}
//add other methods here
};
spyOn(cache, 'removeAll');
spyOn($cacheFactory, 'get').and.returnValue(cache);
$provide.value('$cacheFactory', $cacheFactory);
});
});
describe('yourFunction', function(){
it('calls cache.remove()', function(){
yourService.yourFunction();
expect(cache.remove).toHaveBeenCalled();
});
});