2

我想在我的AngularJS应用中测试我的Auth服务。每次测试后重置服务对象

这是服务:

'use strict'; 

angular.module('testApp') 
    .factory('Auth', function ($window, $http, $location, $q) { 
     var currentUser; 

     return { 
      authenticate: function (email, password) { 
       //promise to return 
       var deferred = $q.defer(); 

       var authRequest = $http.post('https://' + $location.host() + ':3005/authenticate', {email: email, password: password}); 

       authRequest.success(function (data, status, header, config) { 
        //Store currentUser in sessionStorage 
        currentUser = data; 
        $window.sessionStorage.setItem('currentUser', JSON.stringify(currentUser)); 
        //resolve promise 
        deferred.resolve(); 
       }); 

       authRequest.error(function (data, status, header, config) { 
        //reject promise 
        deferred.reject('Invalid credentials.'); 
       }); 

       return deferred.promise; 
      }, 
      isAuthenticated: function() { 
       return this.getCurrentUser() !== null; 
      }, 
      getCurrentUser: function() { 
       if (currentUser !== undefined) { 
        return currentUser; 
       } else { 
        currentUser = JSON.parse($window.sessionStorage.getItem('currentUser')); 
        return currentUser; 
       } 
      }, 
      logOut: function() { 
       var that = this; 
       $http.get('https://' + $location.host() + ':3005/logout') 
        .success(function (data, status, header, config) { 
         that.appLogOut(); 
         $location.path('/login'); 
        }). 
        error(function (data, status, headers, config) { 
         console.log('logout error'); 
        }); 
      }, 
      appLogOut: function() { 
       console.log('appside log out'); 
       currentUser = null; 
       $window.sessionStorage.removeItem('currentUser'); 
      } 
     }; 
    }); 

这是我的测试:

'use strict'; 

describe('Service: Auth', function() { 

    // load the service's module 
    beforeEach(module('testApp')); 

    // instantiate service and any mock objects 
    var Auth, 
     httpBackend; 

    //http://code.angularjs.org/1.2.14/docs/api/ngMock/function/angular.mock.inject 
    beforeEach(inject(function (_Auth_, $httpBackend) { 
     Auth = _Auth_; 
     httpBackend = $httpBackend; 
    })); 

    // verify that no expectations were missed in the tests 
    afterEach(function() { 
     httpBackend.verifyNoOutstandingExpectation(); 
     httpBackend.verifyNoOutstandingRequest(); 
    }); 

    it('should be instantiated', function() { 
     (!!Auth).should.be.true; 
    }); 

    describe('authenticate(email, password)', function() { 
     var user = { 
      email: 'sha[email protected]', 
      password: 'password', 
      sessionId: 'abc123' 
     }; 

     it('should make a call to the server to log the user in - and FULFILL promise if response == 200', function() { 
      httpBackend.whenPOST(/https:\/\/.+\/authenticate/, { 
       email: user.email, 
       password: user.password 
      }).respond(200, user); 

      var promise = Auth.authenticate(user.email, user.password); 

      httpBackend.flush(); 

      promise.should.eventually.be.fulfilled; 
     });  
    }); 


    describe('isAuthenticated()', function() { 
     it('should return false if user is not authenticated', function() { 
      Auth.isAuthenticated().should.be.false; 
     }); 
    }); 

    describe('logOut()', function() { 
     it('should make a call to the server to log the user out', function() { 
      // expect a GET request to be made 
      // regex to capture all requests to a certain endpoint regardless of domain. 
      httpBackend.expectGET(/https:\/\/.+\/logout/).respond(200); 

      // call the logOut method on Auth service 
      Auth.logOut(); 

      // flush to execute defined mock behavior. 
      httpBackend.flush(); 
     }); 
    }); 

}); 

我的问题是下面的测试:

describe('isAuthenticated()', function() { 
    it('should return false if user is not authenticated', function() { 
     Auth.isAuthenticated().should.be.false; 
    }); 
}); 

据我了解,各'describe'和/或'it'块应该完全独立。我认为每次测试之前都会注入一个新的'Auth'实例。但是,上述测试由于在此测试运行之前成功进行身份验证测试而失败。

因此输出变为:

Chrome 33.0.1750 (Mac OS X 10.8.2) Service: Auth isAuthenticated() should return false if user is not authenticated FAILED 
    expected true to be false 
    AssertionError: expected true to be false 

我缺少什么?我是否必须在每次测试后手动重置Auth对象?我尝试在afterEach()函数中设置Auth = {},但这似乎没有改变任何东西。

感谢您花时间阅读此问题。

更新:

我知道这个问题。在Auth.getCurrentUser()中,我从$ window.sessionStorage中获取'currentUser'。所以,我在每次测试(我认为)都得到一个Auth的新实例,但是使用了$ window.sessionStorage的同一个实例。

问题现在应该是......'每次测试后,我如何清除$ window.sessionStorage'。

回答

2

我结束了嘲讽$窗口对象:测试

beforeEach(function() { 
     // $window mock. 
     windowMock = { 
      sessionStorage: { 
       getItem: sinon.stub(), 
       setItem: sinon.spy(), 
       removeItem: sinon.spy() 
      } 
     }; 

     // stub out behavior 
     windowMock.sessionStorage.getItem.withArgs('currentUser').returns(JSON.stringify(user)); 

     module(function ($provide) { 
      $provide.value('$window', windowMock); 
     }); 
    }); 

例子:

windowMock.sessionStorage.setItem.calledWith('currentUser', JSON.stringify(user)).should.be.true; 

windowMock.sessionStorage.setItem.neverCalledWith('currentUser', JSON.stringify(user)).should.be.true; 
+1

shaunlimü救了我从总量和鸡犬不宁。你是一个传奇。 – Sam

+0

@shaunlim:你在哪里定义'sinon'? – coblr

相关问题