尝试测试泛型angularjs $ resource服务时出现未知提供程序错误

时间:2015-03-04 07:19:30

标签: angularjs testing jasmine angularjs-service angular-resource

我有为我的应用程序创建资源的通用服务:

(function(module) {
module.provider('restService', {

    resourceRegistry: {},
    addRestResource: function(entityName, entityProto) {
        this.resourceRegistry[entityName] = entityProto;
    },

    $get: function() {
        var restService;
        for (var entityName in this.resourceRegistry) {
            createRestResource(entityName, this.resourceRegistry[entityName]);
        };

        restService = {
            //createRestResource: createRestResource
        };

        return restService;
  }});

  function createRestResource(entityName, entityProto) {
    console.log('registering model: ' + entityName);
    module.provider(entityName, { $get: function($resource, $http) {
        var resource = $resource('/api/' + entityName + '/:id', { // TODO use config
            id : '@id' //this binds the ID of the model to the URL param
        },{
            query : { method : 'GET', isArray : true }, //this can also be called index or all
            update : { method : 'PUT' },
            create : { method : 'POST' },
            destroy : { method : 'DELETE' }
        });

        // here gose some other functionality unrelated to the topic...

        return resource;
    }});
}}(angular.module('restService', ['ngResource'])));

任何其他模块都可以使用

module.config(['restServiceProvider', function(restServiceProvider) {
  restServiceProvider.addRestResource('User', { name: null, email: null });
}

虽然上面实际上在我的应用程序中起作用实际上上面在我的应用程序中都不适用于我(由于重构前留下的一些代码而工作),我也无法工作jasmine / karma测试它。问题是尝试各种方法来配置restServiceProvider我总是以错误结束,说明例如TestEntity有未知的提供者TestEntityProider。虽然我在创建资源之前尝试了不同的方法来配置resourceRegistry,但这里有一些测试文件。

describe('testing restService', function () {
    var httpBackend;
    var theRestServiceProvider;

    beforeEach(function() {
        module('ngResource');
        module('restService');
        var fakeModule = angular.module('test.app.config', ['ngResource'], function () {});
        fakeModule.config( function (restServiceProvider) {
            theRestServiceProvider = restServiceProvider;
            restServiceProvider.addRestResource('TestModel', {testProp: null});
        });

        module('test.app.config');
    });

    beforeEach(function () {
        inject(function ($httpBackend) {
            httpBackend = $httpBackend;
        })
    });

    beforeEach(inject(function (restService) {}));



    describe('create restService entity', function() {
        it('should post entity with nonempty testProp',
            function() {
                theRestServiceProvider.addRestResource('TestModel', {testProp: null});

                inject(function(TestModel) {
                    var object = new TestModel();
                    object.testProp = 'John Doe';

                    httpBackend.expectPOST(/.*/,
                        function(postData) {
                            console.log("post data: " + postData);
                            jsonData = JSON.parse(postData);
                            expect(jsonData.testProp).toBe(object.testProp);

                            return jsonData;
                        }).respond({});

                    var response = object.$create();

                    httpBackend.flush();
                });
            });
    });
});

IMO这是因为在测试中注册资源正在进行太晚了#39;但我仍然不知道如何做到这一点。

此处编辑是最终解决方案快捷方式

(function(module) {
  module.provider('restService', function($provide) {
    var provider = {};
    // all the provider stuff goes here

    function createRestResource(entityName, entityProto) {
      /* 
       * using $provider here is fundamental here to properly create 
       * 'entityName' + Provider in the runtime instead of module initialisation
       * block
       */
       $provide.factory(entityName, function($resource, $http) { /* ... */ };
       // do other stuff...
    }

    return provider;
  }
}(angular.module('restServiceModule', ['ngResource'])))

2 个答案:

答案 0 :(得分:1)

我在https://github.com/tunguski/matsuo-ng-resource/blob/master/matsuo-ng-resource.js做了非常类似的事情,也许它会对你有帮助。

基本上我将新的资源提供程序添加到$provide而不是module。有用。我认为这是主要区别。

答案 1 :(得分:0)

我对karma / jasmine不太熟悉,但BDD语法似乎相似。 根据我的理解,你应该有这样的东西

beforeEach(function () {
    module('restService');
    inject(function (_$httpBackend_, _restService_, _ngResource_) {
        $httpBackend = _$httpBackend_;
        restService = _restService_;
        ngResource = _ngResource_;
    })
});

而不是你beforeEach。阅读更多here。 如果你想提供模拟而不是注入服务,你可以使用

    module('restService', function($provide){
        $provide.value('serviceToMock', mockObject);
    });

请注意,命名模块和具有相同名称的提供者/服务/工厂可能会在以后阶段混淆......