Angularjs 使用$http对Angular指令进行单元测试

Angularjs 使用$http对Angular指令进行单元测试,angularjs,jasmine,Angularjs,Jasmine,我有一个Angular指令,当附加到时,在用户输入后等待一秒钟,然后用$http查询端点。简而言之,它的目的是检查用户名的唯一性 看起来是这样的: .directive('sgValidUsername', ['$http', function(http) { var waitTimer; var checkIfUserExists = function(e, ctrl) { http.get('/publicapi/users/' + e.target.

我有一个Angular指令,当附加到
时,在用户输入后等待一秒钟,然后用$http查询端点。简而言之,它的目的是检查用户名的唯一性

看起来是这样的:

.directive('sgValidUsername', ['$http', function(http) {
    var waitTimer;
    var checkIfUserExists = function(e, ctrl) {
            http.get('/publicapi/users/' + e.target.value + '/exists')
                .success(function(data) {
                    ctrl.$setValidity('unique', !data.exists);
            });
        };

    return {
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, element, attrs, ctrl) {
            element.on('blur keyup', function(e) {
                if (e.target.value) {
                    clearInterval(waitTimer);
                    waitTimer = setTimeout(function() {
                        checkIfUserExists(e, ctrl);
                    }, 1000);
                }
            });
        }
    };
}]);
我正在尽力编写一个好的全面的Jasmine单元测试套件,但没有成功,因为我找不到合适的例子来学习。我最终以测试的形式重构指令,而不是实际测试指令。此外,我还收到一个“无待处理的刷新请求”错误

对下面的问题有什么建议吗

describe('SignupForm directives', function () { 
    var form,       // el to which directive is applied
    $scope,
    $httpBackend, // $http mock
    usernameExistsHandler;

beforeEach(function() {
    module('signupform.directives');
});

beforeEach(function() {
    inject(function ($injector, $rootScope, $compile, $q, $timeout) {
        $scope = $rootScope;
        $httpBackend = $injector.get('$httpBackend');
        usernameExistsHandler = $httpBackend.whenGET(/\/publicapi\/users\/.+?\/exists/);
        var el = angular.element('<form name="form"><input type="text" name="username" ng-model="user.username" sg-username-is-valid /></form>');

        $scope.user = { username: null };
        $compile(el)($scope);
        form = $scope.form;
    });
});

afterEach(function() {
 $httpBackend.verifyNoOutstandingExpectation();
 $httpBackend.verifyNoOutstandingRequest();
   });

   it('should invalidate with existing usernames', function() {
    form.username.$setViewValue('username_in_use');

    $scope.$digest();

    expect($scope.user.username).toEqual('username_in_use');

    usernameExistsHandler.respond('200', { exists: true });
    $httpBackend.expectGET('/publicapi/users/' + $scope.user.username + '/exists/');
    $httpBackend.flush();

    expect(form.username.$valid).toBe(false);
   });
descripe('SignupForm指令',函数(){
var form,//el指令应用到的对象
$scope,
$httpBackend,/$http模拟
用户名existshandler;
beforeach(函数(){
模块('signupform.directives');
});
beforeach(函数(){
注入(函数($injector、$rootScope、$compile、$q、$timeout){
$scope=$rootScope;
$httpBackend=$injector.get(“$httpBackend”);
usernameExistsHandler=$httpBackend.whenGET(/\/publicapi\/users\/.+?\/exists/);
var el=角度元素(“”);
$scope.user={username:null};
$compile(el)($scope);
form=$scope.form;
});
});
之后(函数(){
$httpBackend.VerifyNoOutstandingExpection();
$httpBackend.verifyNoOutstandingRequest();
});
它('should invalidate with existing usernames',function()){
form.username.$setViewValue('username_in_use');
$scope.$digest();
expect($scope.user.username).toEqual('username\u in\u use');
respond('200',{exists:true});
$httpBackend.expectGET('/publicapi/users/'+$scope.user.username+'/exists/');
$httpBackend.flush();
expect(form.username.$valid).toBe(false);
});

您是否考虑过将$http调用移动到服务/工厂中,只监视对工厂的调用,而不是直接在指令中使用$http?您不必将$http服务测试和指令测试混合在一起。@m.brand:我考虑过,但这似乎不合适,因为此指令和建议的服务都不适用可能会在其他地方重复使用。如果没有更好的解决方案,我当然可以回到这一点上,但目前它似乎只是额外的项目混乱和过度设计。好吧,你的文件最终将被合并/缩小,所以我真的会将它们拆分。测试小单元总是比较容易的。