在AngularJS中测试$resource服务

在AngularJS中测试$resource服务,angularjs,angular-resource,Angularjs,Angular Resource,我正试图开始为angular应用程序编写单元测试,但由于不确定如何以可测试的方式模拟我的服务,我很快就遇到了瓶颈。 有没有办法模仿REST调用?否则,我需要在测试中反映我服务中的所有内容,这对我来说似乎不合适,但我对测试写作相当陌生,所以可能这就是应该如何完成的。任何帮助都将不胜感激 我的服务如下: angular.module('resources.users', ['ngResource']) .factory('User', function($resource) { var res

我正试图开始为angular应用程序编写单元测试,但由于不确定如何以可测试的方式模拟我的服务,我很快就遇到了瓶颈。
有没有办法模仿REST调用?否则,我需要在测试中反映我服务中的所有内容,这对我来说似乎不合适,但我对测试写作相当陌生,所以可能这就是应该如何完成的。任何帮助都将不胜感激

我的服务如下:

angular.module('resources.users', ['ngResource'])
.factory('User', function($resource) {
   var resource = $resource('/api/index.php/users/:username', {}, {
      'update': {method: 'PUT'}
   });

   resource.getUser = function(username, successCb) {
      return resource.query({username: username}, successCb);
   };

   return resource;
});
到目前为止,我的测试包括:

describe('User', function() {
    var mockUserResource;
    beforeEach(module('resources.users'));
    beforeEach(function() {
        mockUserResource = sinon.stub({
            getUser: function(username) {
                mockUserResource.query({username: username});
            },
            query: function() {}
        });
        module(function($provide) {
            $provide.value('User', mockUserResource);
        })
   });
   describe('getUser', function() {
      it('should call getUser with username', inject(function(User) {
          User.getUser('test');
          expect(mockUserResource.query.args[0][0]).toEqual({username: 'test'});
      }));
   })
});

您可以模拟ngResource发出的请求,如下所示:

describe('User', function () {
    var mockUserResource, $httpBackend;
    beforeEach(angular.mock.module('myApp'));

    beforeEach(function () {
        angular.mock.inject(function ($injector) {
            $httpBackend = $injector.get('$httpBackend');
            mockUserResource = $injector.get('User');
        })
    });

    describe('getUser', function () {
        it('should call getUser with username', inject(function (User) {
            $httpBackend.expectGET('/api/index.php/users/test')
                .respond([{
                username: 'test'
            }]);

            var result = mockUserResource.getUser('test');

            $httpBackend.flush();

            expect(result[0].username).toEqual('test');
        }));

    });
});
beforeEach(angular.mock.inject(function ($injector) {
    $httpBackend = $injector.get('$httpBackend');
    mockUserResource = $injector.get('User');
}));

极大地帮助我理解了这一点,但我想进一步介绍它的工作原理。如果它被编辑,我在这里再次列出代码:

describe('User', function () {
    var mockUserResource, $httpBackend;
    beforeEach(angular.mock.module('myApp'));

    beforeEach(function () {
        angular.mock.inject(function ($injector) {
            $httpBackend = $injector.get('$httpBackend');
            mockUserResource = $injector.get('User');
        })
    });

    describe('getUser', function () {
        it('should call getUser with username', inject(function (User) {
            $httpBackend.expectGET('/api/index.php/users/test')
                .respond([{
                username: 'test'
            }]);

            var result = mockUserResource.getUser('test');

            $httpBackend.flush();

            expect(result[0].username).toEqual('test');
        }));

    });
});
这是怎么回事? 1. 我们告诉角度注入器(and)注入
myApp
模块中定义的内容。您可以将其视为定义模块依赖项而不定义依赖模块。比较如何将
myApp
模块中定义的内容注入
angular.module('myOtherApp',['myApp'])
模块中的控制器

2. 在每个规范之前,使用注入的依赖项运行
函数($injector)
函数。在这种情况下,依赖项(
$injector
)是从参数名隐式解析的。此代码段的功能等效变体为

beforeEach(function () {
    angular.mock.inject(['$httpBackend', 'User', function ($httpB, User) {
        $httpBackend = $httpB;
        mockUserResource = User;
    }]);
});
在这里,我们显式地声明了依赖项,并且可以自由地使用我们想要的任何参数名

3. 同样,test函数被作为参数注入隐式解析的
User
服务,尽管它实际上没有被使用

请注意,这次在
inject
调用周围没有包装函数<如果规范当前正在运行,code>inject将立即调用传递的函数,但如果没有,它将返回一个包装函数(请参阅inject和),因此我们实际上不需要包装函数。因此,我们可以在上面的每个片段之前编写
,如下所示:

describe('User', function () {
    var mockUserResource, $httpBackend;
    beforeEach(angular.mock.module('myApp'));

    beforeEach(function () {
        angular.mock.inject(function ($injector) {
            $httpBackend = $injector.get('$httpBackend');
            mockUserResource = $injector.get('User');
        })
    });

    describe('getUser', function () {
        it('should call getUser with username', inject(function (User) {
            $httpBackend.expectGET('/api/index.php/users/test')
                .respond([{
                username: 'test'
            }]);

            var result = mockUserResource.getUser('test');

            $httpBackend.flush();

            expect(result[0].username).toEqual('test');
        }));

    });
});
beforeEach(angular.mock.inject(function ($injector) {
    $httpBackend = $injector.get('$httpBackend');
    mockUserResource = $injector.get('User');
}));

令人惊叹的!如果没有你,我会怎么做呢?莎莎?布莱恩:一起想办法总是很好的@这是sza+1。我有一个类似的问题,在最近的一个版本(Angular 1.2和Karma 0.10.2)中使用JSONP。测试本身的唯一问题是,断言的值是模拟数据。结果[0]。用户名的值始终为“test”,因此它有点毫无意义。此测试应验证$scope是否受结果影响。我得到“意外请求:get”。/../someTemplateURL.html”如果我添加$httpBackend.flush(),则不需要更多请求。有什么想法吗?你能解释一下sinon.stub吗?我最初使用sinon来删除函数,但后来没有使用它,因为它似乎不需要。()
beforeEach(angular.mock.inject(function ($injector) {
    $httpBackend = $injector.get('$httpBackend');
    mockUserResource = $injector.get('User');
}));