javascript - 每次测试后重置服务对象

标签 javascript angularjs unit-testing angularjs-service karma-runner

我正在尝试在 AngularJS 应用程序中测试我的身份验证服务。

这是服务:

'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: '<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="acdfc4cdd9c2ecd8c9dfd882cfc3c1" rel="noreferrer noopener nofollow">[email protected]</a>',
            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;
    });
});

据我了解,每个“描述”和/或“它” block 应该完全独立。我认为在每次测试之前都会注入(inject)一个新的“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”。

最佳答案

我最终 mock 了 $window 对象:

    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;

关于javascript - 每次测试后重置服务对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22647958/

相关文章:

javascript - 将 javascript 文件与 html 集成 - 简单示例

caching - AngularJS 在开发机器上禁用部分缓存

javascript - angularjs 使用 ng-repeat 从 i18n 翻译下拉列表

ruby-on-rails - 跳过 Ruby on Rails 中的测试单元不起作用

javascript - mocha javascript单元测试返回html字符串的函数

python - 在 Python 中模拟 ImportError

javascript - 将 Mongoose/Multer 文件上传的工作 Modal/FORM 更改为 MULTIPART/FORM - Modal 保持打开状态

javascript - 我如何在具有重复行的表单中使用名称和 ID

javascript - 遍历数组

javascript - 表达 + AngularJS : app hangs on invalid url