Ogólnie zgadzam z odpowiedzią Dave'a Newtona powyżej. Jednak istnieją pewne skrajne przypadki tego podejścia, które należy wziąć pod uwagę.
Take odmianę do rozwiązania Dave'a, z innym przypadku testowego:
// production code
var Klass = function() {
this.call_count = 0;
this.called_method();
};
Klass.prototype.called_method = function() {
++this.call_count;
};
// test code
describe("The Klass constructor", function() {
it("should call its prototype's called_method", function() {
spyOn(Klass.prototype, 'called_method');
var k = new Klass();
expect(k.called_method).toHaveBeenCalled();
});
it('some other test', function() {
var k = new Klass();
expect(k.call_count).toEqual(1);
});
});
Drugi test zakończy się niepowodzeniem, ponieważ konfiguracja szpieg w pierwszej próbie utrzymuje poza granice testowych do drugiej metody; Metoda named_method nie zwiększa wartości call_count, więc this.call_count nie ma sobie równych 1. Można również wymyślić scenariusze z fałszywymi pozytywami - testy, które kończą, które nie powinny. Poza tym, ponieważ szpieg pozostaje, im więcej utworzonych instancji Klass, tym większa ilość pamięci, którą szpieg zużyje, ponieważ szpieg zapisuje każde wywołanie metody called_method. To prawdopodobnie nie stanowi problemu w większości przypadków, ale powinieneś być tego świadomy, na wszelki wypadek.
Prostym rozwiązaniem tego problemu byłoby upewnienie się, że szpieg został usunięty po jego użyciu. To może wyglądać nieco brzydki, ale coś jak to działa:
// test code
describe("The Klass constructor", function() {
it("should call its prototype's called_method", function() {
var spy = jasmine.createSpy('called_method');
var method = Klass.prototype.called_method;
Klass.prototype.called_method = spy;
var k = new Klass();
expect(spy).toHaveBeenCalled();
Klass.prototype.called_method = method;
});
[UWAGA - trochę opinia skończyć] Lepszym rozwiązaniem byłoby zmienić sposób pisać kod produkcyjny, aby kod łatwiejsze do testowania. Co do zasady szpiegowanie prototypów jest prawdopodobnie zapachem kodu, którego należy unikać. Zamiast tworzyć instancję zależności w konstruktorze, należy je wstrzyknąć. Zamiast wykonywać inicjalizację w konstruktorze, należy odłożyć do odpowiedniej metody init.
dziękuję za to. najlepszy opis jaki widziałem przez cały dzień na ten temat. – Subimage
Miałem przeczucie, że istnieje uzasadnione rozwiązanie tego problemu. Dziękuję Ci. – BradGreens
Istnieją dwa problemy z tym podejściem. Po pierwsze, powoduje to przeciek pamięci - metoda named_method będzie śledzić wszystkie przyszłe instancje klasy Klass, a ponieważ będzie wykonywanych więcej połączeń, wzrośnie zużycie pamięci przez szpiega. Po drugie, a co ważniejsze, potencjalnie powoduje to wiele testów, które przesłuchują Klassa, aby wchodzić w interakcje ze sobą, ponieważ szpieg został już wezwany. Powinieneś upewnić się, że szpieg został usunięty lub Klass.prototype.called_method zresetowany do oryginalnej metody na końcu sprawy testowej. – alecmce