【问题标题】:How to unit test statetransition in angular?如何以角度对状态转换进行单元测试?
【发布时间】:2016-07-15 02:29:15
【问题描述】:

我正在使用 karma 进行单元测试。我想检查状态转换,所以我创建了这个测试。该应用程序从进入landing 状态开始,然后我想从那里进入main。这是一条安全路由,因此被重定向到login

it('should go to loginpage  before main', function () {
    $scope.$apply();
    expect($state.current.name).toBe('landing');    
    $state.transitionTo('main');
    $scope.$apply();
    expect($state.current.name).toBe('login');
});

在我的 app.js 中,我有:

 $rootScope.$on('$stateChangeStart', function (event,next) {
        console.log('statechange from:', $state.current.name)
        //console.log('statechange to:',$state)

        if (!next.authenticate) {
            return;
        }

        //if next state is secure then check whether user is logged in:

        if (next.authenticate) {
            event.preventDefault();
            $state.transitionTo('login');
            console.log('goto login');
        }


    });

当我使用 karma 运行测试时,我得到:

Chrome 51.0.2704 (Mac OS X 10.11.4) secure tests should go to loginpage  before main FAILED
    Expected '' to be 'landing'.
        at Object.<anonymous> (/Users/dimitri/karma/basic_karma/appSpec.js:23:37)
    Expected '' to be 'login'.

为什么$state.current.name 是空的?

github 参考:https://github.com/dimitri-a/basic_karma

【问题讨论】:

    标签: angularjs unit-testing angular-ui-router karma-jasmine


    【解决方案1】:

    您似乎在尝试测试两种不同的东西。首先,您正在测试$stateChangeStart-event 是否被触发。其次,您正在测试您的自定义处理程序和其中的逻辑,如果它在需要时重定向。

    单元测试是关于测试应用程序的一小部分。 $stateChangeStart-event 不是您的应用程序的一部分,因为它是 ui-router 组件的一部分。测试此事件是否触发不是您的责任。更好; ui-router 制作了自己的测试用例来检查$stateChangeStart 是否被解雇。您可以亲自查看它们right here。您可以相当肯定事件会在需要时触发。

    那么,我们如何测试您自己的自定义逻辑?首先,我们需要重构$rootScope.$on 处理程序。

    $rootScope.$on('$stateChangeStart', handleStateChange);
    
    function handleStateChange(event, next) {
        console.log('statechange from:', $state.current.name)
        //console.log('statechange to:',$state)
    
        if (!next.authenticate) {
            return;
        }
    
        //if next state is secure then check whether user is logged in:
    
        if (next.authenticate) {
            event.preventDefault();
            $state.transitionTo('login');
            console.log('goto login');
        }
    }
    

    这样,我们将您的自定义逻辑与 Angular $rootScope 分离,我们可以自行测试逻辑。不用担心,当状态即将改变时,您的逻辑仍然会运行。

    接下来是测试本身。我们不必处理$state.transitionTo,因为我们没有测试应用程序的那部分(同样,ui-router 对$state.transitionTo 有自己的测试)。我们甚至不需要使用$scope.$apply

    describe('handleStateChange()', function() {
    
        var $state;
    
        beforeEach(inject(function(_$state_) {
            $state          = _$state_;
    
            // we spy on the $state.transitionTo method, to check if it 
            // has been called by our test case.
            spyOn($state, 'transitionTo');
        }));
    
        it('should transition to login state when authenticate:true', function () {
            // arrange
            var next = {
                name: 'main',
                authenticate: true
            };
    
            // act
            handleStateChange({}, next);
    
            // assert
            // in case of authenticate: true, $state.transitionTo should 
            // have been called with the 'login' name
            expect($state.transitionTo).toHaveBeenCalledWith('login');
        });
    
        it('should not transition to login state when authenticate:false', function () {
            // arrange
            var next = {
                name: 'landing',
                authenticate: false
            };
    
            // act
            handleStateChange({}, next);
    
            // assert
            expect($state.transitionTo).not.toHaveBeenCalledWith('login');
        });
    
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-15
      • 1970-01-01
      • 2017-12-01
      • 1970-01-01
      • 2021-03-11
      • 2020-07-10
      • 1970-01-01
      • 2016-05-15
      相关资源
      最近更新 更多