Mit Jasmine eine Funktion ohne Objekt ausspionieren

154

Ich bin neu bei Jasmine und habe gerade angefangen, es zu benutzen. Ich habe eine Bibliothek js-Datei mit vielen Funktionen, die keinem Objekt zugeordnet sind (dh global sind). Wie spioniere ich diese Funktionen aus?

Ich habe versucht, Fenster / Dokument als Objekt zu verwenden, aber der Spion hat nicht funktioniert, obwohl die Funktion aufgerufen wurde. Ich habe auch versucht, es wie folgt in ein gefälschtes Objekt zu wickeln:

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

und testen mit

expect(fakeElement.fakeMethod).toHaveBeenCalled();

Dies funktioniert auch nicht, da der Spion nicht funktioniert hat

Chetter Hummin
quelle

Antworten:

155

Wenn Sie Ihre Funktion definieren:

function test() {};

Dann ist dies gleichbedeutend mit:

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

Sollte also spyOn(window, 'test')funktionieren.

Wenn dies nicht der Fall ist, sollten Sie auch in der Lage sein:

test = jasmine.createSpy();

Wenn keines davon funktioniert, läuft etwas anderes mit Ihrem Setup.

Ich glaube nicht, dass Ihre fakeElementTechnik funktioniert, weil sich hinter den Kulissen etwas abspielt. Die ursprüngliche globalMethod zeigt immer noch auf denselben Code. Was Spionage tut, ist Proxy, aber nur im Kontext eines Objekts. Wenn Sie Ihren Testcode über das fakeElement aufrufen können, würde es funktionieren, aber dann könnten Sie globale fns aufgeben.

ndp
quelle
2
Es funktionierte! Ich glaube, der Fehler, den ich früher gemacht habe, war, dass ich spyOn mit method () anstelle von method aufgerufen habe. Vielen Dank!
Chetter Hummin
3
Ich hatte einige Probleme bei der Verwendung von spyOn (Fenster, 'Test') mit Chuzpe zum Ausführen der Tests als Teil unserer Automatisierung, da 'Fenster' nicht zugewiesen wurde. Mit jasmine.createSpy () wurde dies umgangen.
Henners
7
jasmine.createSpy () hat bei mir perfekt funktioniert. Vielen Dank!
dplass
1
verwendet test = jasmine.createSpy();, um eckige auszuspionieren $anchroScrollfunktionierte perfekt
Edgar Martinez
1
Aus irgendeinem Grund kann ich nicht zur Arbeit kommen, aber es ist durchaus möglich, dass ich versuche, eine vorhandene Fensterfunktion zu verspotten. $window.open(url, '_blank');mit der Absicht, einen neuen Tab (oder ein neues Fenster, je nach Browser-Setup) zu öffnen. Wie soll ich sicherstellen, dass diese Funktion aufgerufen wird und überprüft wird, ob unabhängig vom Browser zur richtigen URL navigiert wird?
CSS
71

TypeScript-Benutzer:

Ich weiß, dass das OP nach Javascript gefragt hat, aber für alle TypeScript-Benutzer, die darauf stoßen und eine importierte Funktion ausspionieren möchten, können Sie Folgendes tun.

Konvertieren Sie in der Testdatei den Import der Funktion wie folgt:

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

x = foo(y);

Dazu:

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

x = FooFunctions.foo(y);

Dann kannst du ausspionieren FooFunctions.foo:)

spyOn(FooFunctions, 'foo').and.callFake(...);
// ...
expect(FooFunctions.foo).toHaveBeenCalled();
Alexander Taylor
quelle
3
Vielen Dank für den TypeScript-Hinweis. Sollte für ES6 / Babel genauso sein, aber ich habe es nicht ausprobiert.
Hgoebl
1
Scheint nur zu funktionieren, wenn die Funktion explizit mit dem Alias ​​FooFunctions aufgerufen wird . Ich habe eine Funktionsleiste (), die eine Fabrik ist, die baz () zurückgibt, und möchte testen, dass baz () foo () aufruft. Diese Methode scheint in diesem Szenario nicht zu funktionieren.
Richard Matsen
4
Dies funktioniert, wenn der Alias ​​in foo_functions verwendet wird export const FooFunctions = { bar, foo }; und der Import im Test zu wird. import { FooFunctions } from '../foo_functions'. Der Alias ​​muss jedoch weiterhin explizit in der privaten Implementierung von foo_functions verwendet werden, damit der Spion funktioniert. const result = FooFunctions.foo(params)// Spion meldet Anruf const result = foo(params)// Spion meldet keinen Anruf
Richard Matsen
2
Lief wie am Schnürchen! Danke, du hast mir viel Zeit gespart!
SrAxi
1
Dies funktioniert nicht mehr bekam einenError: <spyOn> : parseCookie is not declared writable or has no setter
Ling Vu
42

Es gibt 2 Alternativen, die ich benutze (für Jasmin 2)

Dieser ist nicht ganz explizit, weil es scheint, dass die Funktion tatsächlich eine Fälschung ist.

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

Die zweite ausführlicher, expliziter und "sauberer":

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

-> Jasmin-Quellcode , um das zweite Argument zu sehen

IxDay
quelle
Dies ist etwas sinnvoller und bricht weit genug aus, um mit Erfolg zu duplizieren. +1 von mir. Danke, C§
CSS
9

Ein sehr einfacher Weg:

import * as myFunctionContainer from 'whatever-lib';

const fooSpy = spyOn(myFunctionContainer, 'myFunc');
FlavourScape
quelle
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();
            })

Das hat bei mir funktioniert.

Sushil
quelle
4
Bitte fügen Sie Ihrer Antwort eine Erklärung hinzu. Der Code selbst ist für die Person, die die Frage stellt, nicht so hilfreich, wenn sie nicht verstehen kann, was los ist.
Chevybow
0

Meine Antwort unterscheidet sich geringfügig von @FlavorScape darin, dass ich im importierten Modul eine einzige (Standardexport-) Funktion hatte. Ich habe Folgendes getan:

import * as functionToTest from 'whatever-lib';

const fooSpy = spyOn(functionToTest, 'default');
IonicBurger
quelle