2017-10-27 114 views
9

UI yönlendiricinin en son kararlı sürümüne geçiş yapıyorum ve belirli durum adları geçişe geçtiğinde belirli bir mantığı gerçekleştirmek için $ geçişler yaşam döngüsü kancalarını kullanıyorum . Daha önce ben bazı devlet adı olarak birlikte $ rootScope bir durum değişikliği olayı yayınlayan olur, denetleyici benim birim testlerindeUI-yönlendirici ile geçiş kancaları nasıl test edilir 1.0.x

this.$transitions.onStart({ }, (transition) => { 
    if (transition.to().name !== 'some-state-name') { 
     //do stuff here... 
    } 
}); 

:

Yani benim denetleyicileri bazılarında bu tür şimdi bir şey var olay test etmek için ihtiyacım olan koşullara çarpıyor.

örn. Doğru yolu şimdi testlerde $transitions.onStart(...) kanca tetiklemek için neyin bu durum olaylara yana

$rootScope.$broadcast('$stateChangeStart', {name: 'other-state'}, {}, {}, {}); 

, kullanımdan kaldırılmıştır?

Testlerimde yalnızca $state.go('some-state-name') numaralı telefonu aramayı denedim, ancak geçiş kancası geri arama işlevi dahilinde hiçbir zaman kendi mantığımı kullanamıyorum. here no'lu belgelere göre, state.go'yu çağırmak, yanlış okuma yapmadığım sürece programlı olarak bir geçişi tetiklemeli mi?

Başarıyla yeni kullanıcı arabirimi 1.0.x için çalışan denetleyicilerin geçiş kancaları için birim sınamaları almayı başardı mı?

bir geçiş kanca kullanarak kontrolör kod

için tam bir örnek:

this.$transitions.onSuccess({ }, (transition) => { 
     this.setOpenItemsForState(transition.to().name); 
    }); 

Test numuneleri:

describe('stateChangeWatcher', function() { 
     beforeEach(function() { 
     spyOn(vm, 'setOpenItemsForState').and.callThrough(); 
     }); 

     it('should call the setOpenItemsForState method and pass it the state object', function() { 
     $state.go('home'); 
     $rootScope.$apply(); 
     expect(vm.setOpenItemsForState).toHaveBeenCalledWith('home'); 
     }); 
    }); 

Casusum asla oluyor uygulamayı çalıştırırken isabet yerel bu kanca alıyor beklendiği gibi çağrıldı, bu yüzden testlerimde yanlış ayarlanmış bir şey olmalı. OnSuccess olayına girdiğim için geçişin testte başarılı olmasını sağlamak için fazladan bir şey var mı?

Teşekkür

GÜNCELLEME

Ben Gitter üzerinde ui-yönlendirici odasında bu kaldırdı ve repo katkı sahiplerinden biri aslında koştu benim testlerde $state.go('home') çağrısını kontrol düşündüren bana geri döndü Test özelliklerime expect($state.current.name).toBe('home'); ekleyerek. ,

enter image description here

Bu konuda nasıl devam etmek emin değilim:

Bu benim testte benim için geçmesi yok, ama yine de geçiş kanca geri aramasında benim işlevine çağrı vurmak alamıyorum önceki kodumu kullanabilmem için eski $ stateChange olayları için polyfill'u yüklemek dışında, bunu yapmamayı ve $ geçiş kancalarını test etmenin uygun yolunu bulmayı tercih ediyorum.Estus' cevabı takiben

GÜNCELLEME 2

, şimdi $transitions hizmet söndürdü ve aynı zamanda benim denetleyicisi özel adlandırılmış fonksiyonu içine benim geçiş kanca işleyicisi refactored var: Şimdi

export class NavBarController { 
    public static $inject = [ 
    '$mdSidenav', 
    '$scope', 
    '$mdMedia', 
    '$mdComponentRegistry', 
    'navigationService', 
    '$transitions', 
    '$state' 
    ]; 

    public menuSection: Array<InterACT.Interfaces.IMenuItem>; 

    private openSection: InterACT.Interfaces.IMenuItem; 
    private openPage: InterACT.Interfaces.IMenuItem; 

    constructor(
    private $mdSidenav, 
    private $scope, 
    private $mdMedia, 
    private $mdComponentRegistry, 
    private navigationService: NavigationService, 
    private $transitions: any, 
    private $state 
) { 
    this.activate(); 
    } 

    private activate() { 
    this.menuSection = this.navigationService.getNavMenu(); 
    if (this.isScreenMedium()) { 
     this.$mdComponentRegistry.when('left').then(() => { 
     this.$mdSidenav('left').open(); 
     }); 
    } 
    this.setOpenItemsForState(this.$state.$current.name); 
    this.$transitions.onSuccess({ }, this.onTransitionsSuccess); 
    } 

    private onTransitionsSuccess = (transition) => { 
    this.setOpenItemsForState(transition.to().name); 
    } 

    private setOpenItemsForState(stateName: string) { 
     //stuff here... 
    } 
} 

benim test spesifikasyonum var:

describe('Whenever a state transition succeeds', function() { 
     beforeEach(function() { 
     spyOn(vm, 'setOpenItemsForState').and.callThrough(); 
     $state.go('home'); 
     }); 
     it('should call the setOpenItemsForState method passing in the name of the state that has just been transitioned to', function() { 
     expect($transitions.onSuccess).toHaveBeenCalledTimes(1); 
     expect($transitions.onSuccess.calls.mostRecent().args[0]).toEqual({}); 
     expect($transitions.onSuccess.calls.mostRecent().args[1]).toBe(vm.onTransitionsSuccess); 
     }); 
    }); 

Bu beklentiler geçiyor ama yine de yapamıyorum Benim adlı kanca geri aramasında burada yanlış yapıyorum setOpenItemsForState

enter image description here

için bir çağrı yapmak onTransitionsSuccess fonksiyonunu içimdeki mantığı vurmak için?

GÜNCELLEME 3

tekrar Estu için

sayesinde, sadece benim adında geçiş kanca işlevi ayrı bir testtir çağırabilir unutuyordum:

describe('and the function bound to the transition hook callback is invoked', function(){ 
     beforeEach(function(){ 
      spyOn(vm, 'setOpenItemsForState'); 
      vm.onTransitionsSuccess({ 
      to: function(){ 
       return {name: 'another-state'}; 
      } 
      }); 
     }); 
     it('should call setOpenItemsForState', function(){ 
      expect(vm.setOpenItemsForState).toHaveBeenCalledWith('another-state'); 
     }); 
     }); 

Ve şimdi% 100 kapsama almak :)

enter image description here

Umarım bu diğerleri için iyi bir referans olarak hizmet verecek Kendi geçiş kancalarını nasıl test edeceğimizi öğrenmek için uğraşanlar olabilir.

cevap

2

AngularJS yönlendirmesi için iyi bir birim test stratejisi, yönlendiriciyi tamamen kestirmektir. Gerçek yönlendirici, ünitelerin verimli bir şekilde test edilmesini önler ve gereksiz hareketli parçalar ve beklenmedik davranışlar sağlar. ngMock gerçek uygulamadan farklı davrandığından, bu tür testler de uygun entegrasyon testleri olarak değerlendirilemez.

Kullanımdaki tüm yönlendirici hizmetleri kesilmelidir. $stateProvider saplama o state çağrı üzerine kendisini dönmelidir ve $get çağrı $state saplama dönmelidir yani temel davranış yansıtmalıdır:

let mockedStateProvider; 
let mockedState; 
let mockedTransitions; 

beforeEach(module('app')); 

beforeEach(module(($provide) => { 
    mockedState = jasmine.createSpyObj('$state', ['go']); 
    mockedStateProvider = jasmine.createSpyObj('$stateProvider', ['state', '$get']); 
    mockedStateProvider.state.and.returnValue(mockedStateProvider); 
    mockedStateProvider.$get.and.returnValue(mockedState); 
    $provide.provider('$state', function() { return mockedStateProvider }); 
})); 

beforeEach(module(($provide) => { 
    mockedTransitions = jasmine.createSpyObj('$transitions', ['onStart', 'onSuccess']); 
    $provide.value('$transitions', mockedTransitions); 
})); 

bir test dostu yolu geri aramaları olarak bağlanmış yöntemleri yerine anonim fonksiyonları sağlamaktır :

:

this.onTransitionStart = (transition) => { ... }; 
this.$transitions.onStart({ }, this.onTransitionStart); 

Sonra yöntemler sadece uygun argümanlarla denildiği test edilebilir stubbed

Geri arama işlevi, beklenen argümanlarla arayarak doğrudan test edilebilir. Bu, tam kapsama alanı sağlar ancak insan hatası için bir yer bırakır, ünite testleri gerçek yönlendirici ile entegrasyon/e2e testleri ile yedeklenmelidir.

+0

Yanıt ve büyük açıklama için teşekkürler - şimdi çok anlam ifade ediyor. Ben dev makinemin önünde değilim ama bunu denemek için heyecanlıyım! – mindparse

+0

Önerilen yaklaşımınıza bir adım attım ancak çağrıyı işleyicime tam olarak kapatmaya çalışırken sorunlarla karşılaşıyorum. Burada temel bir şeyi kaçırdığımı hissediyorum, yardımcı olabilir misiniz? – mindparse

+0

Sorun nedir?Bunu “this.onTransitionStart” ({to:() => ({name: ...})}) 'gibi beklenen hatalarla ve dahili mantığına göre casus olarak adlandırırsınız, (ctrl.setOpenItemsForState) .toHaveBeenCalledWith (. ..) '. – estus