我应该用$ http服务测试这个Angularjs Login控制器?

时间:2016-08-20 23:18:22

标签: angularjs unit-testing jasmine tdd karma-jasmine

我正在做一个简单的应用程序(角度生成器),通过带有$ http.get()的Auth工厂登录。如果成功,则使用$ localStorage在本地设置“sessionId”值。一切正常,但我在单元测试方面存在严重问题。我无法在脑海中定义我应该测试什么! 这是我的情况。

控制器/ logincontrollers.js

angular.module('myApp')
.controller('LoginCtrl',['$rootScope', '$scope', '$location', '$localStorage', 'Auth', function ($rootScope, $scope, $location, $localStorage, Auth) {

  Auth.Logout();
  $rootScope.loginSucceeded = false;
  $scope.currentUser = {};

  $scope.login = function () {
    var formData = {
      username: $scope.username,
      password: $scope.password
    };

    Auth.Login(formData).then(function (response) {
      if (response.data.loginSucceeded === true && response.data.sessionId !== null) {
        $scope.currentUser = {username: $scope.username, sessionId: response.data.sessionId};
        $localStorage.currentUser = $scope.currentUser;
        $rootScope.loginSucceeded = true;
        window.location = '/';
      } else {
        $scope.error = 'Invalid credentials';
      }
    }, function (response) {
      $scope.error = 'Connection error';
      console.log(response);
    });
  };

}]);

服务/ auth.js

angular.module('myApp')
.constant('baseURL', 'http://localhost:8080')
.factory('Auth',['$http', '$localStorage', 'baseURL', function ($http, $localStorage, baseURL) {

  return {
    Login: function (data) {
      return $http.get(baseURL + '/login', {
        params: data
      });
    },
    Logout: function () {
      delete $localStorage.currentUser;
    }
  };

}]);

服务器仅接受带有查询参数的登录请求

http://localhost:8080/login?username=Test&password=Test

现在关键点。 这就是我在测试中所做的没有错误。

测试/规格/ logincontroller.js

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

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

  var scope, $httpBackend, LoginCtrl;

  // Initialize the controller and a mock scope
  beforeEach(inject(function ($rootScope, _$httpBackend_, $controller, Auth) {
    $httpBackend = _$httpBackend_;
    scope = $rootScope.$new();
    LoginCtrl = $controller('LoginCtrl', {
      $scope: scope, Auth: Auth
      // place here mocked dependencies
    });
  }));
  afterEach(function() {
    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();
  });


  it('should fetch sessionId', function() {
    $httpBackend.when('GET', 'http://localhost:8080/login', {params: {username: "Test", password: "Test"}})
    .respond({"sessionId":"c4b0b46a04b54247ac27f3bd4db289a0","loginSucceeded":true});
    scope.login();
    $httpBackend.flush();
  });

});

我尝试做的每一件事都给了我一个错误。 你能帮我理解这个测试是否合适,我应该测试什么?也许是形式,还是$ localStorage还是什么? 你有一个严肃的单元测试手册/资源/最佳实践建议我吗?

感谢您的建议。

---更新---

You can explain why if i do this test:

it('should fetch sessionId', function() {
    $httpBackend.when('GET', 'http://localhost:8080/login', {params: {username: "Test", password: "Test"}})
    .respond({sessionId:"c4b0b46a04b54247ac27f3bd4db289a0",loginSucceeded:true});
    scope.login();
    expect(scope.sessionId).toEqual('c4b0b46a04b54247ac27f3bd4db289a0');
    $httpBackend.flush();
  });

我收到了这个错误:

PhantomJS 2.1.1 (Mac OS X 0.0.0) Controller: LoginCtrl should fetch sessionId FAILED
        Expected undefined to equal 'c4b0b46a04b54247ac27f3bd4db289a0'.
        test/spec/controllers/logincontroller.js:44:36
        loaded@http://localhost:8081/context.js:151:17
PhantomJS 2.1.1 (Mac OS X 0.0.0): Executed 5 of 5 (1 FAILED) (0.008 secs / 0.063 secs)

1 个答案:

答案 0 :(得分:1)

关于测试的一般经验法则是这个

  • 测试您正在测试的内容。如果您只是在测试Controller测试
  • 为此目的,模拟其他一切,在您的情况下,这将是auth服务。

单独测试auth服务并遵循类似的模式,模拟$ http服务等等。

所以我说你不是一百万英里之外,只是把它分成两个不同的测试套件(文件)。

嘲讽我倾向于使用$provide来创建一个空对象,然后使用我需要的函数spy并模拟数据的返回。这样,您就可以准确地知道要调用的内容以及应返回的数据。

这方面的一个例子是:

module(function($provide) {
  $provide.service('Auth', function() {
    this.logIn = jasmine.createSpy('logIn').andCallFake(function(params) {
      //a fake implementation
    });
    this.logOut = jasmine.createSpy('logOut').andCallFake(function(params) {
      //a fake implementation
    });
  });
});

这样做的好处是你可以断言/期望函数被调用如此

expect(Auth.LogIn).toHaveBeenCalled();

您还可以执行更高级的操作,例如检查是否使用特定参数调用它。有很多关于此的易于访问的内容,你可以谷歌,现在你知道要寻找什么。

请注意,上面的代码是手写的,因此可能会有轻微的错误。这是一个显示Jasmine v2可以做的good website