在AngularJS中测试$ resource服务

Bri*_*ian 37 angularjs angular-resource

我正在尝试开始为我的角度应用程序编写单元测试并快速点击停止块,因为我不确定如何以可测试的方式模拟我的服务.
有没有办法模拟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;
});
Run Code Online (Sandbox Code Playgroud)

我的测试到目前为止:

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'});
      }));
   })
});
Run Code Online (Sandbox Code Playgroud)

zs2*_*020 54

您可以像这样模拟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');
        }));

    });
});
Run Code Online (Sandbox Code Playgroud)

Demo

  • 测试本身唯一的问题是声明的值是模拟数据.result [0] .username总是会有'test'的值,所以它有点毫无意义.此测试应验证$ scope是否已受结果影响. (3认同)

Emi*_*erg 30

zsong的回答极大地帮助我理解了这一点,但我想扩展它的工作原理.如果它被编辑,我在这里再次列出代码:

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');
        }));

    });
});
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?

1

beforeEach(angular.mock.module('myApp'));
Run Code Online (Sandbox Code Playgroud)

我们告诉Angular注入器($injectorangular.mock.inject)注入myApp模块中定义的东西.您可以将其视为定义没有依赖模块的模块依赖关系.比较myApp模块中定义的内容如何注入模块中的控制器angular.module('myOtherApp', ['myApp']).

2

beforeEach(function () {
    angular.mock.inject(function ($injector) {
        $httpBackend = $injector.get('$httpBackend');
        mockUserResource = $injector.get('User');
    })
});
Run Code Online (Sandbox Code Playgroud)

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

beforeEach(function () {
    angular.mock.inject(['$httpBackend', 'User', function ($httpB, User) {
        $httpBackend = $httpB;
        mockUserResource = User;
    }]);
});
Run Code Online (Sandbox Code Playgroud)

在这里,我们明确地声明了依赖关系,并且可以自由地使用我们希望的任何参数名称.

3

it('should call getUser with username', inject(function (User) {
Run Code Online (Sandbox Code Playgroud)

同样,测试函数使用隐式解析的User服务作为参数注入,但实际上并未使用它.

请注意,这次inject调用周围没有包装函数.inject如果规范当前正在运行,则立即调用传递的函数,否则它返回一个包装函数(参见注入文档源代码),因此我们实际上不需要包装器函数.因此,我们可以beforeEach像这样编写上面的代码片段:

beforeEach(angular.mock.inject(function ($injector) {
    $httpBackend = $injector.get('$httpBackend');
    mockUserResource = $injector.get('User');
}));
Run Code Online (Sandbox Code Playgroud)