Angularjs 如何测试工厂?

Angularjs 如何测试工厂?,angularjs,unit-testing,caching,Angularjs,Unit Testing,Caching,我在角度服务中使用$resource。 我希望使用基于$cacheFactory的自定义缓存,而不是内置的$http缓存,以便在REST服务返回响应时操作缓存 我在单元测试中模拟$cacheFactory时遇到了很大的困难,有人能帮我为我的测试定义正确的模拟和设置吗 下面是我试图测试的代码的简化版本。请注意,我正在告诉我的angular应用程序在myApp.run中使用自定义缓存“DefaultCache”,而不是默认的$http缓存。我理解这是替换所有$resource服务的默认缓存的方法 代

我在角度服务中使用$resource。 我希望使用基于$cacheFactory的自定义缓存,而不是内置的$http缓存,以便在REST服务返回响应时操作缓存

我在单元测试中模拟$cacheFactory时遇到了很大的困难,有人能帮我为我的测试定义正确的模拟和设置吗

下面是我试图测试的代码的简化版本。请注意,我正在告诉我的angular应用程序在myApp.run中使用自定义缓存“DefaultCache”,而不是默认的$http缓存。我理解这是替换所有$resource服务的默认缓存的方法

代码 测试 这是我的测试设置。注意:提供的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' }] });
        });

    });
});
因此,我认为我的mock是错误的,因此我将提供的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
请帮忙 我真的不明白在我的mock中需要什么来满足使用我的mock的代码。它似乎需要一些javascript二元性,我不知道如何在我的mock定义中进行模仿


有人知道我的模拟应该如何构建吗?或者我在这里还遗漏了什么?

对于以后遇到同样问题的人

我找不到任何方法来构建适用于此代码的mock。我甚至从github获得了$cacheFactory的实现,剥离了它的实现,并尝试使用它作为模拟,将其插入测试。那里也没有运气

然而,我确实遇到了一篇随机的帖子,暗示也许我应该在我自己的服务中创建一个cachingservice,它将使用$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) { },
};

对于任何一个后来有同样问题的人

我找不到任何方法来构建适用于此代码的mock。我甚至从github获得了$cacheFactory的实现,剥离了它的实现,并尝试使用它作为模拟,将其插入测试。那里也没有运气

然而,我确实遇到了一篇随机的帖子,暗示也许我应该在我自己的服务中创建一个cachingservice,它将使用$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) { },
};

下面的代码将允许您在单元测试中模拟$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();
    });
});

下面的代码将允许您在单元测试中模拟$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();
    });
});

今天,我在同一个问题上苦苦挣扎,找到了一个不同的解决方案。角度1.3.13

显然$cacheFactory有一个get方法,因此您可以检索cacheId的实例。 这将使您能够监视正确的缓存实例

beforeEach(inject(function (_$cacheFactory_) {
  mockCache = _$cacheFactory_.get('defaultCache');
}));

今天,我在同一个问题上苦苦挣扎,找到了一个不同的解决方案。角度1.3.13

显然$cacheFactory有一个get方法,因此您可以检索cacheId的实例。 这将使您能够监视正确的缓存实例

beforeEach(inject(function (_$cacheFactory_) {
  mockCache = _$cacheFactory_.get('defaultCache');
}));