2014-09-24 19 views
18

Aslında, aşağıdaki işlevlerin aslında bu denetleyicinin jasmine kullanılarak başlatılmasının denendiğini test etmek istiyorum. Görünüşe göre bir casus kullanmak gibi görünüyor, sadece bir 'it' bloğunda çağrıldığını beklediğimde beklediğim gibi çalışmıyor. Bir kapsam fonksiyonu içinde çağrılmadığında bir şey çağrılıp çağrılmadığını kontrol etmenin özel bir yolu olup olmadığını merak ediyorum, sadece kontrolörün kendisinde.Açısal denetleyici başlatıldığında çalıştırılan işlev kapsamındaki casus işlevi

App.controller('aCtrl', [ '$scope', function($scope){ 

    $scope.loadResponses = function(){ 
     //do something 
    } 

    $scope.loadResponses(); 

}]); 

// özellik dosyası

describe('test spec', function(){ 

    beforeEach(
    //rootscope assigned to scope, scope injected into controller, controller instantiation.. the expected stuff 

     spyOn(scope, 'loadResponses'); 
    ); 

    it('should ensure that scope.loadResponses was called upon instantiation of the controller', function(){ 
     expect(scope.loadResponses).toHaveBeenCalled(); 
    }); 
}); 
+3

Genellikle çalışır, ancak bu durumda olmaz. Çünkü denetleyici başlatıldıktan ve yöntemi çağırdıktan sonra casus kurarsınız. Kapsamlı bir casus yöntemi oluşturmuş olsanız bile, denetleyici oluşturulduğunda üzerine yazılacak ve gerçekten işe yaramayacaktır. – PSL

+0

Bunu düşündüğümde, başlatma işleminde '$ scope.loadResponses 'çağrıldığını test etmeniz gerekmez. Çünkü, kontrol cihazının anlık hale getirilmesi başarılı olursa (testlerinizden hiçbiri geçmeyecek olsa bile), '$ scope.loadResponses' çağrıldığından emin olabilirsiniz. Yani başlatma fonksiyonu üzerinde casusluk bir nokta görmüyorum. – PSL

+1

Yolun aşağısında, bir geliştiricinin sayfanın kullanımı için kritik bir kaynak aldığından (istemeyerek) kaldırmasını istemiyorum. Bir değişkenin başlatıldıktan sonra beklenen değere atanmış olduğunu kontrol edebiliyorum, biraz şaşırma, bir casusluk çağrısını kontrol etmek için kullanamıyorum. –

cevap

4

örnekleme üzerine yürütmek kontrolör fonksiyonlarını test etmek yoludur: başarıyla kapsamına sahip fonksiyonu üzerine ispiyonlanacağı

kod budur.

DÜZENLEME: Daha fazlası var. Yorumun işaret ettiği gibi, ctrl örnekleme sırasında işlev mevcut değildir. Bu aramayı gizlemek için, değişkene isteğe bağlı bir işlev atamanız gerekir (bu durumda, kapsam bloğunuzdan sonra, ancak denetleyiciyi başlatmadan ÖNCE kurulum bloğunuzda scope.getResponses öğesini boş bir işleve atayabilirsiniz). Daha sonra casus yazmanız gerekir (tekrar kurulum bloğunuzda ve ctrl örneğinden ÖNCE) ve son olarak denetleyiciyi başlatabilir ve bu işleve bir çağrı yapılmasını bekleyebilirsiniz. İlk başta

+1

Zenorbi'nin cevabı, bunun nasıl doğru ayarlanacağına dair çok daha fazla ayrıntı içeriyor, ama bu doğru cevap. Zenorbi'nin öncesinde, kapsamı “$ digest” i çağırmadan önce casusunuzu spyOn (kapsam, 'loadResponses') 'ile kurun ve iyi durumda olmalısınız. –

+4

bana hiç bir anlam ifade etmiyor. init'ten önce, işlev mevcut değil - casusluk yapacak hiçbir şey yok. Eğer önceden bir casus atarsak, init içinde geçersiz kılınır .. –

+0

@guymograbi Daha iyi açıklamak için cevabı güncelledim ... önceki cevap yanıltıcıydı, özür dilerim. –

9

Oluşturduğunuz kapsamı ile kontrolör kendinizi çalıştırmalısınız. Bunun Sorun şu ki, kodunuzu yeniden yapılandırmanız gerekiyor. Var olmayan bir işlevin üzerinde casusluk yapamazsınız, ancak işlev çağrılmadan önce casus olmanız gerekir. Eğer bunu yapamaz beri

$scope.loadResponses = function(){ 
    //do something 
} 
// <-- You would need your spy attached here 
$scope.loadResponses(); 

, başka bir yerde $scope.loadResponses() arama yapmak gerekir. (BeforeEach cinsinden) kontrolör örnekleme önce casus Ayar

var scope; 
beforeEach(inject(function($controller, $rootScope) { 
    scope = $rootScope.$new(); 
    $controller('aCtrl', {$scope: scope}); 
    scope.$digest(); 
})); 
it("should have been called", function() { 
    spyOn(scope, "loadResponses"); 
    scope.doTheStuffThatMakedLoadResponsesCalled(); 
    expect(scope.loadResponses).toHaveBeenCalled(); 
}); 
+7

'loadResponses' denir. Anladığım kadarıyla sorunun tam anlamı buydu: “Aşağıdaki denetleyicinin başlatılmasında aşağıdaki fonksiyonun denendiğini test etmek istiyorum”. Bir tavuk <-> yumurta durumu gibi görünüyor. – PSL

0

'daki berbat cevabı için özür dilerim. Yukarıdaki cevaplardan hiçbirini anlamadım.

yöntem sık sık kullanmak - Eğer loadResponses aslında ne belirtmediniz .. bunun yerine yapar çıktı test

test yoktur .. ama kapsamına şey koyar diyelim - böylece deney varlığı Bunun .. BTW

- kendimi benzer bir soru sordu ama hala casusluk istiyorsanız izole kapsamına angular - how to test directive with isolatedScope load?

- bir izole olmayan kapsamına, kesinlikle bir teknik kullanabilirsiniz ..

örneğin, kod

if (!$scope.loadResponses){ 
    $scope.loadResponses = function(){} 
} 

$scope.loadResponses(); 

Eğer kontrolör başlatılıyor önce casus tanımlamak mümkün olacak Bu şekilde olmasını değiştirin.

Başka bir yol, yorumlarda PSL'nin önerdiği gibidir - loadResponses'u bir servise götürün, casusluk yapın ve çağrıldığını kontrol edin.

Bununla birlikte, belirtildiği gibi, bu izole bir kapsam üzerinde çalışmayacaktır .. ve bu yüzden her iki senaryona cevap verdiği için gerçekten tavsiye ettiğim tek şey test etme yöntemidir.

2

Bu tür senaryoları test etmeyi bulmamın tek yolu, sınanacak yöntemi ayrı bir bağımlılığa taşımaktır, daha sonra denetleyiciye enjekte eder ve bunun yerine sınamalarda sahte olmasını sağlar. İşte

çok temel bir çalışma örneğidir: muhtemelen (örneğin, her zaman sahte loadResponses yönteme istemese de) ekstra çalışma gerekecektir gerçek dünya kodu için

angular.module('test', []) 
    .factory('loadResponses', function() { 
     return function() { 
      //do something 
     } 
    }) 
    .controller('aCtrl', ['$scope', 'loadResponses', function($scope, loadResponses) { 
     $scope.loadResponses = loadResponses; 

     $scope.loadResponses(); 
    }]); 

describe('test spec', function(){ 
    var scope; 
    var loadResponsesInvoked = false; 

    var fakeLoadResponses = function() { 
     loadResponsesInvoked = true; 
    } 

    beforeEach(function() { 
     module('test', function($provide) { 
      $provide.value('loadResponses', fakeLoadResponses) 
     }); 

     inject(function($controller, $rootScope) { 
      scope = $rootScope.$new(); 
      $controller('aCtrl', { $scope: scope }); 
     }); 
    }); 

    it('should ensure that scope.loadResponses was called upon instantiation of the controller', function() { 
     expect(loadResponsesInvoked).toBeTruthy(); 
    }); 
}); 

, ama fikir olsun .

Ayrıca

, burada aslında Yasemin casusları kullanmak sahte bağımlılıkları nasıl oluşturulacağını açıklayan bir güzel makale: Mocking Dependencies in AngularJS Tests

DÜZENLEME: İşte$provide.delegate kullanır ve orijinal bir yöntem yerine geçmez alternatif yoldur:

describe('test spec', function(){ 
    var scope, loadResponses; 
    var loadResponsesInvoked = false; 

    beforeEach(function() { 
     var loadResponsesDecorator = function ($delegate) { 
      loadResponsesInvoked = true; 
      return $delegate; 
     } 

     module('test', function($provide) { 
      $provide.decorator('loadResponses', loadResponsesDecorator); 
     }); 

     inject(function($controller, $rootScope) { 
      scope = $rootScope.$new(); 
      $controller('aCtrl', { $scope: scope }); 
     }); 
    }); 

    it('should ensure that scope.loadResponses was called upon instantiation of the controller', function() { 
     expect(loadResponsesInvoked).toBeTruthy(); 
    }); 
}); 
İlgili konular