如何对具有多个 $resource 调用的 angular 控制器进行单元测试

How to unit test angular controller having multiple $resource calls

我有一个控制器在初始化时对后端执行多个 $resource 调用。这工作正常,但现在我需要用 jasmine 添加单元测试,问题来了,当我尝试在控制器中保存对象的状态时出现错误。

在控制器初始化时,我进行了 3 次 $resource 调用以填充 3 个下拉菜单,在对 3 个下拉菜单进行选择并在另一个输入文本中输入一个值后,我按下提交(保存)并保存了我的实体。

我对 angular 没有太多经验,所以我真的需要帮助,如果需要其他资源,请尽管提出,我会将它们添加到此 post。谢谢!

现在我需要对这个保存函数进行单元测试,但出现错误:

Chrome 41.0.2272 (Windows 7) permissionController should call the service successfully FAILED
        Error: Unexpected request: POST http://localhost:8080/webapp-1.0.0-SNAPSHOT/v1/actions/search
        No more request expected
            at $httpBackend (C:/_workspace/webapp/Platform/ui/src/main/uidev/node_modules/angular-mocks/angular-mocks.js:1220:9)
            at sendReq (C:/_workspace/webapp/Platform/ui/src/main/uidev/app/lib/js/angular.js:9628:9)
            at serverRequest (C:/_workspace/webapp/Platform/ui/src/main/uidev/app/lib/js/angular.js:9344:16)
            at processQueue (C:/_workspace/webapp/Platform/ui/src/main/uidev/app/lib/js/angular.js:13189:27)
            at C:/_workspace/webapp/Platform/ui/src/main/uidev/app/lib/js/angular.js:13205:27
            at Scope.$eval (C:/_workspace/webapp/Platform/ui/src/main/uidev/app/lib/js/angular.js:14401:28)
            at Scope.$digest (C:/_workspace/webapp/Platform/ui/src/main/uidev/app/lib/js/angular.js:14217:31)
            at Function.$httpBackend.flush (C:/_workspace/webapp/Platform/ui/src/main/uidev/node_modules/angular-mocks/angular-mocks.js:1519:38)
            at Object.<anonymous> (C:/_workspace/webapp/Platform/ui/src/main/uidev/test/unit/authz/permission/create-permission-controller-test.js:28:21)

这是控制器:

angular.module('platform.authz').controller('permissionController', function($translatePartialLoader,
 PermissionService, ActionService, ResourceService, EnvironmentService, $scope, $state) {

'use strict';
$translatePartialLoader.addPart('authz/permission');

var controller = this;
controller.permission = {};

function errorMessageHandler(response) {
    var errorMessages = [];
    response.data.messages.forEach(function(message, i) {
        errorMessages[i] = {type: 'danger', text: message.description};
    });
    controller.notificationMessages = errorMessages;
}

controller.populateActions = function() {
    ActionService.searchRequestObject().search({search: ''}).$promise.then(function(data) {
        controller.actions = data;
    }, errorMessageHandler);
};

controller.populateResources = function() {
    ResourceService.searchRequestObject().search({search: ''}).$promise.then(function(data) {
        controller.resources = data;
    }, errorMessageHandler);
};

controller.populateEnvironments = function() {
    EnvironmentService.searchRequestObject().search({search: ''}).$promise.then(function(data) {
        controller.environments = data;
    }, errorMessageHandler);
};

controller.getPermissionSaveRequest = function() {
    var permissionSaveRequest = {};
    permissionSaveRequest.name = controller.permission.name;
    permissionSaveRequest.actionId = controller.permission.action.id;
    permissionSaveRequest.resourceId = controller.permission.resource.id;
    permissionSaveRequest.environmentId = controller.permission.environment.id;
    return permissionSaveRequest;
};

controller.save = function() {
    PermissionService.createRequestObject().create(controller.getPermissionSaveRequest()).$promise.then(function() {
        controller.notificationMessages = [
            {type: 'success', text: 'Save has been successful!'}
        ];
        controller.permission = {};
        $scope.permissionDetailsForm.$setPristine();
    }, errorMessageHandler);
};

controller.cancel = function cancel() {
    $state.reload();
};

controller.actions = controller.populateActions();
controller.resources = controller.populateResources();
controller.environments = controller.populateEnvironments();
});

这是在控制器初始化时调用的服务之一(所有 3 个服务看起来都一样)

angular.module('platform.authz').factory('ActionService', function($resource, $log, configService) {
'use strict';

return {
    searchRequestObject: function() {
        return $resource(configService.getUrlForService('action') + '/' + 'search', {}, {
            search: {method: 'POST', isArray: true}
        });
    }
    };
});

这是我的单元测试试用版:

describe('permissionController', function() {
'use strict';

var httpBackend, permissionController, state, scope;

beforeEach(module('platform'));

beforeEach(inject(function(_$httpBackend_, $controller, _$state_, configService, $rootScope) {
    state = _$state_;
    spyOn(state, 'go');
    spyOn(state, 'transitionTo');
    spyOn(configService, 'getUrlForService')
            .and.callFake(function(name) {
                return CONFIG.get('MAIN_URL_FOR_REST_SERVICES') + name + 's';
            }
    );
    httpBackend = _$httpBackend_;
    scope = $rootScope.$new();
    permissionController = $controller('permissionController', {$scope: scope});
}));

it('should call the service successfully', function() {
    permissionController.permission = {'name': 'all', 'action': {'id': 1, 'name': 'all'}, 'resource': {'id': 1, 'name': 'all'}, 'environment': {'id': 1, 'name': 'all'}};
    httpBackend
        .whenPOST(CONFIG.get('MAIN_URL_FOR_REST_SERVICES') + 'permissions', permissionController.getPermissionSaveRequest())
        .respond(200, 'created');
    permissionController.save();
    httpBackend.flush();
    expect(permissionController.errorMessages[0].text).toBe('Error');
    });
});

问题是您在加载控制器时进行了 3 次 $resource 调用,在执行测试时加载了控制器。所以你应该确保(例如在 beforeEach 中)也模拟那些后端调用。您现在只在按下保存时模拟您期望的那个,但在保存事件之前,您的控制器已经在进行一些后端通信。你得到的例外是告诉你这个:"unexpected request".

修复在这里:

describe('permissionController', function() {
'use strict';

var $httpBackend, permissionController, scope;

beforeEach(module('platform'));

beforeEach(inject(function($injector, _$state_, configService) {
    $httpBackend = $injector.get('$httpBackend');
    scope = $injector.get('$rootScope').$new();
    scope.permissionDetailsForm = {$setPristine: function() {
    }};

    var state = _$state_;
    spyOn(state, 'go');
    spyOn(state, 'transitionTo');
    spyOn(configService, 'getUrlForService')
            .and.callFake(function(name) {
                return CONFIG.get('MAIN_URL_FOR_REST_SERVICES') + name + 's';
            }
    );

    var $controller = $injector.get('$controller');

    $httpBackend.when('POST', CONFIG.get('MAIN_URL_FOR_REST_SERVICES') + 'actions/search').respond(200,
            '[{"name": "all","id": "1"}]'
    );
    $httpBackend.when('POST', CONFIG.get('MAIN_URL_FOR_REST_SERVICES') + 'resources/search').respond(200,
            '[{"name": "all","id": "1"}]'
    );
    $httpBackend.when('POST', CONFIG.get('MAIN_URL_FOR_REST_SERVICES') + 'environments/search').respond(200,
            '[{"name": "all","id": "1"}]'
    );

    permissionController = $controller('permissionController', {$scope: scope});
    $httpBackend.flush();
}));

it('should call the service successfully', function() {
    permissionController.permission =
        {'name': 'all', 'action': {'id': 1, 'name': 'all'}, 'resource': {'id': 1, 'name': 'all'},
         'environment': {'id': 1, 'name': 'all'}};
    $httpBackend
            .whenPOST(CONFIG.get('MAIN_URL_FOR_REST_SERVICES') + 'permissions',
                permissionController.getPermissionSaveRequest())
            .respond(200, 'created');
    permissionController.save();
    $httpBackend.flush();
    expect(permissionController.notificationMessages[0].text).toBe('Save has been successful!');
});
});