这是我的控制器的一部分:

    $scope.isLoggedIn = function () {
        return Boolean($sessionStorage.isLoggedIn);
    };

    $scope.login = function () {
        //If the browser fills in the username and password field then angular's model will not be updated so we need
        //to manually pull them out of the DOM :(. See this issue for details: https://github.com/angular/angular.js/issues/1460
        var username = $('#usernameInput').val();
        var password = $('#passwordInput').val();
        $scope.loginErrMsg = null;

        $http.jsonp("http://ldap-auth.otpp.me" + '/login?callback=JSON_CALLBACK&username=' + encodeURIComponent(username) + '&password=' + encodeURIComponent(password))
            .success(function (data, isLoggedIn) {
                // This app is for internal use only, security is not a major concern.
                // So using sessionStorage to store the login status is OK.
                $sessionStorage.displayName = data.displayName;
                $sessionStorage.isLoggedIn = true;
            })
            .error(function () {
                $scope.loginErrMsg = "Invalid username or password";
            });
    };


这是我的测试:

describe('Controller: MainCtrl', function () {

// load the controller's module
beforeEach(module('uiappApp'));

var MainCtrl,
    $httpBackend,
    scope;

// Initialize the controller and a mock scope
beforeEach(inject(function ($injector, $controller, $rootScope) {
    scope = $rootScope.$new();
    MainCtrl = $controller('MainCtrl', {
        $scope: scope
    });
    $httpBackend = $injector.get('$httpBackend');

}));
it('should login', function () {
    var isLoggedIn = scope.isLoggedIn();
    expect(isLoggedIn).toBe(false);

    var username = $('<input type="text" id="usernameInput"/>');
    var password = $('<input type="text" id="passwordInput"/>');
    $('body').html('<div>')
        .find('div')
        .append(username)
        .append(password);
    username.val('username');
    password.val('password');
    var response =  $httpBackend.expectJSONP('http://ldap-auth.otpp.me/login?callback=JSON_CALLBACK&username=username&password=password');
    response.respond({displayName: 'userX'}, {'A-Token': 'xxx'});
    scope.login();
    expect(scope.isLoggedIn()).toEqual(true);
    $('body').empty();
    });
});


但是,测试始终会失败(Expected false to equal true.)。看来我没有让$ httpBackend工作。但是我不知道哪里出了问题。基本上,我想在单元测试时模拟$ http.jsonp()响应以提供模拟的json,然后测试用户登录。

非常感谢您的帮助!

@HackedByChinese在您迈出第一步之后,我得到了:

it('should login', function () {
    var isLoggedIn = scope.isLoggedIn();
    expect(isLoggedIn).toBe(false);

    var username = $('<input type="text" id="usernameInput"/>');
    var password = $('<input type="text" id="passwordInput"/>');
    $('body').html('<div>')
        .find('div')
        .append(username)
        .append(password);
    username.val('username');
    password.val('password');
    var response =  $httpBackend.expectJSONP('http://ldap-auth.otpp.me/login?callback=JSON_CALLBACK&username=username&password=password');
    response.respond({displayName: 'userX'}, {'A-Token': 'xxx'});
    scope.login();
    $httpBackend.flush();
    expect(scope.isLoggedIn()).toEqual(true);
    $('body').empty();
});


但是我收到以下错误消息:

    Error: Unexpected request: GET views/main.html
No more request expected
    at $httpBackend (C:/repo/docserver-ui/UIApp/app/bower_components/angular-mocks/angular-mocks.js:1177:9)
    at sendReq (C:/repo/docserver-ui/UIApp/app/bower_components/angular/angular.js:7967:9)
    at $get.serverRequest (C:/repo/docserver-ui/UIApp/app/bower_components/angular/angular.js:7708:16)
    at deferred.promise.then.wrappedCallback (C:/repo/docserver-ui/UIApp/app/bower_components/angular/angular.js:11100:81)
    at deferred.promise.then.wrappedCallback (C:/repo/docserver-ui/UIApp/app/bower_components/angular/angular.js:11100:81)
    at C:/repo/docserver-ui/UIApp/app/bower_components/angular/angular.js:11186:26
    at Scope.$get.Scope.$eval (C:/repo/docserver-ui/UIApp/app/bower_components/angular/angular.js:12175:28)
    at Scope.$get.Scope.$digest (C:/repo/docserver-ui/UIApp/app/bower_components/angular/angular.js:12004:31)
    at Function.$httpBackend.flush (C:/repo/docserver-ui/UIApp/app/bower_components/angular-mocks/angular-mocks.js:1435:16)
    at null.<anonymous> (C:/repo/docserver-ui/UIApp/test/spec/controllers/main.js:43:22)
Process finished with exit code 0


这是我的部分html:

            <form class="navbar-form navbar-right" role="form" ng-show="!isLoggedIn()">
                <p class="navbar-text" id="loginErrMsg">{{loginErrMsg}}</p>
                <div class="form-group">
                    <input type="text" placeholder="User Name" id="usernameInput"
                           class="form-control"
                           ng-class="{'error-fields': loginErrMsg}">
                </div>
                <div class="form-group">
                    <input type="password" placeholder="Password" id="passwordInput" class="form-control" ng-class="{'error-fields': loginErrMsg}">
                </div>
                <button type="submit" class="btn btn-success" ng-click="login()">Sign in</button>
        </form>

最佳答案

在调用scope.login()之后,在expect(...)之前,您需要调用$httpBackend.flush()使其响应以指定的期望值。

这不是特定于JSONP,而是通常对单元测试$http进行调用。

总结一下,这是对发出$http请求的代码进行单元测试的步骤:


使用$httpBackend设置您的期望。
调用进行$http调用的代码。
调用$httpBackend.flush(),使其以您设置的期望响应任何未决请求。
进行测试断言。


有关刷新,请参见docs

09-20 21:06