如何通过jasmine避免在角度测试中的location.reload(),并测试它

时间:2015-01-08 11:13:07

标签: angularjs testing jasmine

在我的一个控制器中,我有一个location.reload()

(对于那些想知道原因的人,我的登录页面在用户登录之前不会加载整个应用程序以降低服务器上的阈值)

当我测试控制器(使用jimine html作为ui)时,它实际上是在无限循环中重新加载测试。

我的问题是:

如何避免location.reload()加载测试本身,以及如何检查它是否已被调用?我能以某种方式嘲笑它吗?

这是控制器的代码:

(function() {
    'use strict';

    angular
    .module('app.ctrls')
    .controller('LoginController', LoginController);

    LoginController.$inject = [ '$scope', 'AuthService' ];

    function LoginController($scope, AuthService)
    {
        console.log('LoginController');
        $scope.credantials = {
                email:      '',
                password:   '',
                remember:   false
        }
        $scope.login = function(credantials)
        {
            AuthService.login(credantials.email, credantials.password, credantials.remember || false).success(function(response) {
                console.log(response);
                if (response.email !== null)
                {
                    $scope.logged = true;
                    console.log('login successful');
                    location.reload();
                }
                else
                {
                    $scope.logged = false;
                    $scope.error = true;
                }
            }).error(function() {
                console.log('failed to login');
            });
        };
    }
})();

这是规范:

describe("successfully logged in", function() {
    it("should reload the page", function() {
        this.scope.credantials = { email: 'test@mail.com', password: '123', remember: false };
        this.$httpBackend.expectPOST('/auth/login', this.scope.credantials).respond({first_name: "Bakayaru", email: "test@mail.com"});
        this.$httpBackend.whenGET('/tpls/home.html').respond(200);
        this.scope.login(this.scope.credantials);
        this.$httpBackend.flush();
        expect(this.scope).toBeDefined();
        expect(this.scope.logged).toBeTruthy();
        /* -------> TEST that location.reload() has been called HERE <--------- */
    });
});

3 个答案:

答案 0 :(得分:4)

我不确定你的意思是“不加载自己”,但无论如何都可以在测试中模拟.reload()。我在我的应用程序中首先使用Angular服务$ window.location而不是我的应用程序中的本机javascript位置,就像注入$ window后依赖于我的控制器:

$window.location.reload();

然后在spec文件中我有以下内容(使用模拟重新加载的一个示例测试用例):

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

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

  var MyCtrl,
    scope,
    mockBackend,
    window;

  beforeEach(function(){
    inject(function(_$httpBackend_, $controller, $rootScope, $window) {
        scope = $rootScope.$new();
        mockBackend = _$httpBackend_;
        window = $window;
        spyOn(window.location, 'reload');
        myCtrl = $controller('MyCtrl', {
            $scope: scope,
            $window: window
        });
    });
  });

it('logout should fail if $window.reload() is called on unsuccessful logout call', function(){
    scope.logout();
    mockBackend.expectGET('/rest/session/logout').respond(404);

    mockBackend.flush();
    expect(window.location.reload.calls.count()).toEqual(0);

    mockBackend.verifyNoOutstandingExpectation();
    mockBackend.verifyNoOutstandingRequest();
  });
});

这与spec文件的结构有点不同,但我希望这个例子说明如何模拟$ window对象并在其上使用间谍。

答案 1 :(得分:2)

您可以在测试中模拟$ window:

describe('service', function () {

  var $window;

  beforeEach(module('core', function ($provide) {
    $window = {
      location:{
        reload: jasmine.createSpy()
      }
    };
    $provide.value('$window', $window);
  }));

});

这样它将“覆盖”$ window的默认行为。

答案 2 :(得分:1)

我意识到就像PHP中的单元测试一样,例如,当代码有file_get_content时,你必须自己模拟它,而不是测试它。

location.reload是一个浏览器组件,因此必须模拟我的代码才能变得可测试。

因此我创建了BrowserService

(function() {
    'use strict';

    angular
    .module('rushcore.services')
    .factory('BrowserService', BrowserService);

    function BrowserService()
    {
        console.log('BrowserService');
        return {
            reload: function() {
                location.reload();
            }
        };
    }
})();

在测试中我嘲笑并注射它。

var BrowserServiceMock = { reload: function(){ console.log("reloaded"); } };

然后我发现了它:

var reload = spyOn(BrowserServiceMock, 'reload');

最后确定它被称为:

expect(reload).toHaveBeenCalled();