Używanie Jasmine do szpiegowania funkcji bez obiektu

154

Jestem nowy w Jasmine i właśnie zacząłem go używać. Mam plik js biblioteki z wieloma funkcjami, które nie są powiązane z żadnym obiektem (tj. Są globalne). Jak mam szpiegować te funkcje?

Próbowałem użyć okna / dokumentu jako obiektu, ale szpieg nie działał, mimo że funkcja została wywołana. Próbowałem też owinąć go w fałszywy przedmiot w następujący sposób:

var fakeElement = {};
fakeElement.fakeMethod = myFunctionName;
spyOn(fakeElement, "fakeMethod");

i przetestuj z

expect(fakeElement.fakeMethod).toHaveBeenCalled();

To też nie działa, ponieważ szpieg nie działał

Chetter Hummin
źródło

Odpowiedzi:

155

Jeśli definiujesz swoją funkcję:

function test() {};

Wtedy jest to równoważne z:

window.test = function() {}  /* (in the browser) */

Tak spyOn(window, 'test')powinno działać.

Jeśli tak nie jest, powinieneś być w stanie:

test = jasmine.createSpy();

Jeśli żaden z nich nie działa, z twoją konfiguracją dzieje się coś innego.

Myślę, że twoja fakeElementtechnika nie działa z powodu tego, co dzieje się za kulisami. Oryginalny globalMethod nadal wskazuje na ten sam kod. To, co robi szpiegostwo, to proxy to, ale tylko w kontekście obiektu. Jeśli możesz sprawić, by kod testowy wywoływał przez fakeElement, zadziała, ale wtedy będziesz mógł zrezygnować z globalnego fns.

ndp
źródło
2
Zadziałało! Myślę, że błąd, który popełniłem wcześniej, polegał na tym, że wywoływałem spyOn z method () zamiast method. Dzięki!
Chetter Hummin
3
Miałem problemy z używaniem spyOn (okno, „test”), używając hucpa do uruchamiania testów w ramach naszej automatyzacji, ponieważ „okno” nie zostało przypisane. Użycie jasmine.createSpy () pozwoliło obejść ten problem.
Henners
7
jasmine.createSpy () działało idealnie dla mnie. Dzięki!
dplass
1
kiedyś test = jasmine.createSpy();szpiegował angularJs $anchroScrolldziałał idealnie
Edgar Martinez
1
Z jakiegoś powodu nie mogę uruchomić żadnej z tych metod, ale może być całkiem możliwe, że dzieje się tak dlatego, że próbuję wykonać mockowanie istniejącej funkcji okna; $window.open(url, '_blank');z zamiarem otwarcia nowej karty (lub okna w zależności od ustawień przeglądarki). Jak mam się upewnić, że wywołuje tę funkcję i sprawdza, czy przechodzi do właściwego adresu URL niezależnie od przeglądarki?
CSS
71

Użytkownicy języka TypeScript:

Wiem, że OP pytał o javascript, ale dla wszystkich użytkowników TypeScript, którzy zetkną się z tym, którzy chcą szpiegować zaimportowaną funkcję, oto co możesz zrobić.

W pliku testowym przekonwertuj import funkcji z tego:

import {foo} from '../foo_functions';

x = foo(y);

Do tego:

import * as FooFunctions from '../foo_functions';

x = FooFunctions.foo(y);

Wtedy możesz szpiegować FooFunctions.foo:)

spyOn(FooFunctions, 'foo').and.callFake(...);
// ...
expect(FooFunctions.foo).toHaveBeenCalled();
Alexander Taylor
źródło
3
Dzięki za wskazówkę TypeScript. Powinien być taki sam dla ES6 / Babel, ale nie próbowałem tego.
hgoebl
1
Wygląda na to, że działa tylko wtedy, gdy wywołuje się funkcję jawnie z aliasem FooFunctions . Mam funkcję bar (), która jest fabrycznie zwracającą baz () i chcę sprawdzić, czy baz () wywołuje foo (). Ta metoda nie wydaje się działać w tym scenariuszu.
Richard Matsen,
4
To zadziała, jeśli alias zostanie przyjęty do foo_functions, export const FooFunctions = { bar, foo }; a import w teście stanie się import { FooFunctions } from '../foo_functions'. Jednak alias nadal musi być jawnie używany w prywatnej implementacji foo_functions, aby szpieg mógł działać. const result = FooFunctions.foo(params)// raporty szpiegowskie dzwonią const result = foo(params)// raporty szpiegów nie dzwonią
Richard Matsen
2
Działał jak urok! Dzięki, zaoszczędziłeś mi dużo czasu!
SrAxi,
1
To już nie działa.Error: <spyOn> : parseCookie is not declared writable or has no setter
Ling Vu
42

Są 2 alternatywy, których używam (dla jaśminu 2)

Ten nie jest do końca jasny, ponieważ wygląda na to, że funkcja jest w rzeczywistości fałszywa.

test = createSpy().and.callFake(test); 

Drugi, bardziej szczegółowy, wyraźniejszy i „czystszy”:

test = createSpy('testSpy', test).and.callThrough();

-> kod źródłowy jasmine, aby zobaczyć drugi argument

IxDay
źródło
Ma to trochę więcej sensu i przerywa na tyle, aby powielać z sukcesem. +1 ode mnie. Dzięki, C§
CSS
9

Bardzo prosty sposób:

import * as myFunctionContainer from 'whatever-lib';

const fooSpy = spyOn(myFunctionContainer, 'myFunc');
FlavorScape
źródło
1
import * as saveAsFunctions from 'file-saver';
..........
....... 
let saveAs;
            beforeEach(() => {
                saveAs = jasmine.createSpy('saveAs');
            })
            it('should generate the excel on sample request details page', () => {
                spyOn(saveAsFunctions, 'saveAs').and.callFake(saveAs);
                expect(saveAsFunctions.saveAs).toHaveBeenCalled();
            })

To zadziałało dla mnie.

Sushil
źródło
4
Dodaj wyjaśnienie do odpowiedzi, sam kod nie jest zbyt pomocny dla osoby zadającej pytanie, jeśli nie może zrozumieć, co się dzieje.
chevybow
0

Moja odpowiedź różni się nieco od @FlavorScape, ponieważ w zaimportowanym module miałem jedną (domyślną) funkcję eksportu, wykonałem następujące czynności:

import * as functionToTest from 'whatever-lib';

const fooSpy = spyOn(functionToTest, 'default');
IonicBurger
źródło