Scheinfunktionen · Scherz (2023)

Mit Mock-Funktionen können Sie die Verknüpfungen zwischen Code testen, indem Sie die tatsächliche Implementierung einer Funktion löschen, Aufrufe der Funktion (und die in diesen Aufrufen übergebenen Parameter) erfassen und Instanzen von Konstruktorfunktionen bei der Instanziierung mit erfassenneuund ermöglicht die Testzeitkonfiguration von Rückgabewerten.

Es gibt zwei Möglichkeiten, Funktionen zu verspotten: Entweder durch das Erstellen einer Mock-Funktion zur Verwendung im Testcode oder durch das Schreiben einermanuelle Verspottungum eine Modulabhängigkeit zu überschreiben.

Verwendung einer Scheinfunktion

Stellen wir uns vor, wir testen eine Implementierung einer Funktionfür jede, der einen Rückruf für jedes Element in einem bereitgestellten Array aufruft.

forEach.js

Export Funktion für jede(Artikel,Ruf zurück) {
für (lassenIndex= 0;Index<Artikel.Länge;Index++) {
Ruf zurück(Artikel[Index]);
}
}

Um diese Funktion zu testen, können wir eine Mock-Funktion verwenden und den Status des Mocks überprüfen, um sicherzustellen, dass der Rückruf wie erwartet aufgerufen wird.

forEach.test.js

constfür jede= erfordern('./für jede');

constMockCallback=Ist.fn(X => 42 +X);

prüfen('forEach Scheinfunktion', () => {
für jede([0, 1],MockCallback);

// Die Mock-Funktion wurde zweimal aufgerufen
erwarten(MockCallback.verspotten.Anrufe).toHaveLength(2);

// Das erste Argument des ersten Aufrufs der Funktion war 0
erwarten(MockCallback.verspotten.Anrufe[0][0]).sein(0);

// Das erste Argument des zweiten Aufrufs der Funktion war 1
erwarten(MockCallback.verspotten.Anrufe[1][0]).sein(1);

// Der Rückgabewert des ersten Aufrufs der Funktion war 42
erwarten(MockCallback.verspotten.Ergebnisse[0].Wert).sein(42);
});

.verspottenEigentum

Alle Scheinfunktionen haben dieses Besondere.verspotten-Eigenschaft, in der Daten darüber gespeichert werden, wie die Funktion aufgerufen wurde und was die Funktion zurückgegeben hat. Der.verspottenEigenschaft verfolgt auch den Wert vonDasfür jeden Anruf, daher ist es auch möglich, dies zu überprüfen:

constmyMock1=Ist.fn();
constA= neu myMock1();
Konsole.Protokoll(myMock1.verspotten.Instanzen);
// > [ ]

constmyMock2=Ist.fn();
constB= {};
constgebunden=myMock2.binden(B);
gebunden();
Konsole.Protokoll(myMock2.verspotten.Kontexte);
// > [ ]
(Video) Einführung in React Testing [Jest and React Testing Library Tutorial]

Diese Scheinmitglieder sind in Tests sehr nützlich, um festzustellen, wie diese Funktionen aufgerufen, instanziiert werden oder was sie zurückgeben:

// Die Funktion wurde genau einmal aufgerufen
erwarten(someMockFunction.verspotten.Anrufe).toHaveLength(1);

// Das erste Argument des ersten Aufrufs der Funktion war „erstes Argument“.
erwarten(someMockFunction.verspotten.Anrufe[0][0]).sein('erstes Argument');

// Das zweite Argument des ersten Aufrufs der Funktion war 'zweites Argument'
erwarten(someMockFunction.verspotten.Anrufe[0][1]).sein('zweites Argument');

// Der Rückgabewert des ersten Aufrufs der Funktion war 'Rückgabewert'
erwarten(someMockFunction.verspotten.Ergebnisse[0].Wert).sein('Rückgabewert');

// Die Funktion wurde mit einem bestimmten „diesem“ Kontext aufgerufen: dem „element“-Objekt.
erwarten(someMockFunction.verspotten.Kontexte[0]).sein(Element);

// Diese Funktion wurde genau zweimal instanziiert
erwarten(someMockFunction.verspotten.Instanzen.Länge).sein(2);

// Das von der ersten Instanziierung dieser Funktion zurückgegebene Objekt
// hatte eine „name“-Eigenschaft, deren Wert auf „test“ gesetzt war
erwarten(someMockFunction.verspotten.Instanzen[0].Name).sein('prüfen');

// Das erste Argument des letzten Aufrufs der Funktion war „test“
erwarten(someMockFunction.verspotten.letzter Aufruf[0]).sein('prüfen');

Schein-Rückgabewerte

Scheinfunktionen können auch verwendet werden, um während eines Tests Testwerte in Ihren Code einzufügen:

constmeinMock=Ist.fn();
Konsole.Protokoll(meinMock());
// > undefiniert

meinMock.MockReturnValueOnce(10).MockReturnValueOnce('X').MockReturnValue(WAHR);

Konsole.Protokoll(meinMock(), meinMock(), meinMock(), meinMock());
// > 10, 'x', wahr, wahr

Scheinfunktionen sind auch in Code sehr effektiv, der einen funktionalen Continuation-Passing-Stil verwendet. In diesem Stil geschriebener Code hilft dabei, die Notwendigkeit komplizierter Stubs zu vermeiden, die das Verhalten der realen Komponente, für die sie stehen, nachbilden, und stattdessen Werte direkt vor ihrer Verwendung direkt in den Test einzufügen.

constfilterTestFn=Ist.fn();

// Lassen Sie den Mock für den ersten Aufruf „true“ zurückgeben,
// und „false“ für den zweiten Aufruf
filterTestFn.MockReturnValueOnce(WAHR).MockReturnValueOnce(FALSCH);

constErgebnis= [11, 12].Filter(Num => filterTestFn(Num));

Konsole.Protokoll(Ergebnis);
// > [11]
Konsole.Protokoll(filterTestFn.verspotten.Anrufe[0][0]); // 11
Konsole.Protokoll(filterTestFn.verspotten.Anrufe[1][0]); // 12

Bei den meisten realen Beispielen geht es tatsächlich darum, sich eine Scheinfunktion für eine abhängige Komponente zu besorgen und diese zu konfigurieren, aber die Technik ist dieselbe. Versuchen Sie in diesen Fällen der Versuchung zu widerstehen, Logik in Funktionen zu implementieren, die nicht direkt getestet werden.

Spottmodule

Angenommen, wir haben eine Klasse, die Benutzer von unserer API abruft. Die Klasse verwendetAxiosUm die API aufzurufen, wird dann die zurückgegebenDatenAttribut, das alle Benutzer enthält:

user.js

importieren Axios aus 'axios';

Klasse Benutzer {
statisch alle() {
zurückkehrenAxios.erhalten('/users.json').Dann(bzw =>bzw.Daten);
}
}

Export Standard Benutzer;

Um diese Methode nun zu testen, ohne tatsächlich auf die API zuzugreifen (und damit langsame und fragile Tests zu erstellen), können wir die verwendenis.mock(...)Funktion zum automatischen Verspotten des Axios-Moduls.

Sobald wir das Modul verspotten, können wir ein bereitstellenmockResolvedValuefür.erhaltenDas gibt die Daten zurück, gegen die unser Test behaupten soll. Tatsächlich sagen wir, dass wir wollenaxios.get('/users.json')eine gefälschte Antwort zurückgeben.

user.test.js

importieren Axios aus 'axios';
importieren Benutzer aus './users';

Ist.verspotten('axios');

prüfen('sollte Benutzer abrufen', () => {
constBenutzer= [{Name: 'Bob'}];
constbzw= {Daten:Benutzer};
Axios.erhalten.mockResolvedValue(bzw);

// oder Sie könnten je nach Anwendungsfall Folgendes verwenden:
// axios.get.mockImplementation(() => Promise.resolve(resp))

zurückkehren Benutzer.alle().Dann(Daten => erwarten(Daten).gleich(Benutzer));
});

Verspottende Teiltöne

Teilmengen eines Moduls können verspottet werden und der Rest des Moduls kann seine tatsächliche Implementierung behalten:

foo-bar-baz.js

Export constfoo= 'foo';
Export const Bar = () => 'Bar';
Export Standard () => 'baz';
//test.js
importieren defaultExport, {Bar,foo} aus '../foo-bar-baz';

Ist.verspotten('../foo-bar-baz', () => {
constOriginalModul=Ist.requireActual('../foo-bar-baz');

//Den Standardexport simulieren und Export mit dem Namen „foo“ benennen
zurückkehren {
__esModule: WAHR,
...OriginalModul,
Standard:Ist.fn(() => 'verspotteter Baz'),
foo: 'verspotteter Foo',
};
});

prüfen(„sollte eine teilweise Verspottung machen“, () => {
constdefaultExportResult= defaultExport();
erwarten(defaultExportResult).sein('verspotteter Baz');
erwarten(defaultExport).toHaveBeenCalled();

erwarten(foo).sein('verspotteter Foo');
erwarten(Bar()).sein('Bar');
});

Scheinimplementierungen

Dennoch gibt es Fälle, in denen es sinnvoll ist, über die Möglichkeit zur Angabe von Rückgabewerten hinauszugehen und die Implementierung einer Scheinfunktion vollständig zu ersetzen. Dies kann mit erfolgenis.fnoder derMockImplementationOnceMethode für Scheinfunktionen.

constmyMockFn=Ist.fn(cb => cb(Null, WAHR));

myMockFn((irren,val) => Konsole.Protokoll(val));
// > wahr

DerMockImplementationDie Methode ist nützlich, wenn Sie die Standardimplementierung einer Scheinfunktion definieren müssen, die aus einem anderen Modul erstellt wird:

foo.js

Modul.Exporte = Funktion () {
// einige Implementierung;
};

test.js

Ist.verspotten('../foo'); // Dies geschieht automatisch beim Automocking
constfoo= erfordern('../foo');

// foo ist eine Scheinfunktion
foo.MockImplementation(() => 42);
foo();
// > 42

Wenn Sie ein komplexes Verhalten einer Scheinfunktion nachbilden müssen, sodass mehrere Funktionsaufrufe unterschiedliche Ergebnisse liefern, verwenden Sie dieMockImplementationOnceMethode:

constmyMockFn=Ist
.fn()
.MockImplementationOnce(cb => cb(Null, WAHR))
.MockImplementationOnce(cb => cb(Null, FALSCH));

myMockFn((irren,val) => Konsole.Protokoll(val));
// > wahr

myMockFn((irren,val) => Konsole.Protokoll(val));
// > falsch

Wenn der simulierten Funktion die mit definierten Implementierungen ausgehenMockImplementationOnce, wird der Standardimplementierungssatz mit ausgeführtis.fn(falls definiert):

constmyMockFn=Ist
.fn(() => 'Standard')
.MockImplementationOnce(() => 'erster Aufruf')
.MockImplementationOnce(() => 'zweiter Anruf');

Konsole.Protokoll(myMockFn(), myMockFn(), myMockFn(), myMockFn());
// > 'erster Aufruf', 'zweiter Aufruf', 'default', 'default'

Für Fälle, in denen wir Methoden haben, die normalerweise verkettet sind (und daher immer zurückkehren müssen).Das), haben wir eine zuckersüße API, um dies in Form von a zu vereinfachen.mockReturnThis()Funktion, die auch auf allen Mocks sitzt:

constmyObj= {
meineMethode:Ist.fn().mockReturnThis(),
};

// ist das gleiche wie

constotherObj= {
meineMethode:Ist.fn(Funktion () {
zurückkehren Das;
}),
};

Scheinnamen

Sie können optional einen Namen für Ihre Scheinfunktionen angeben, der stattdessen angezeigt wird'is.fn()'in der Testfehlerausgabe. Verwenden.mockName()wenn Sie in der Lage sein möchten, die Scheinfunktion, die einen Fehler in Ihrer Testausgabe meldet, schnell zu identifizieren.

constmyMockFn=Ist
.fn()
.MockReturnValue('Standard')
.MockImplementation(Skalar => 42 +Skalar)
.Scheinname('add42');

Benutzerdefinierte Matcher

Um es weniger anspruchsvoll zu machen, festzustellen, wie Scheinfunktionen aufgerufen wurden, haben wir schließlich einige benutzerdefinierte Matcher-Funktionen für Sie hinzugefügt:

// Die Mock-Funktion wurde mindestens einmal aufgerufen
erwarten(MockFunc).toHaveBeenCalled();

// Die Mock-Funktion wurde mindestens einmal mit den angegebenen Argumenten aufgerufen
erwarten(MockFunc).toHaveBeenCalledWith(arg1,arg2);

// Der letzte Aufruf der Mock-Funktion wurde mit den angegebenen Argumenten aufgerufen
erwarten(MockFunc).toHaveBeenLastCalledWith(arg1,arg2);

// Alle Aufrufe und der Name des Mocks werden als Snapshot geschrieben
erwarten(MockFunc).toMatchSnapshot();

Diese Matcher sind Zucker für gängige Formen der Inspektion.verspottenEigentum. Sie können dies jederzeit manuell selbst tun, wenn Ihnen das besser gefällt oder Sie etwas Spezifischeres tun müssen:

// Die Mock-Funktion wurde mindestens einmal aufgerufen
erwarten(MockFunc.verspotten.Anrufe.Länge).toBeGreaterThan(0);

// Die Mock-Funktion wurde mindestens einmal mit den angegebenen Argumenten aufgerufen
erwarten(MockFunc.verspotten.Anrufe).toContainEqual([arg1,arg2]);

// Der letzte Aufruf der Mock-Funktion wurde mit den angegebenen Argumenten aufgerufen
erwarten(MockFunc.verspotten.Anrufe[MockFunc.verspotten.Anrufe.Länge - 1]).gleich([
arg1,
arg2,
]);

// Das erste Argument des letzten Aufrufs der Mock-Funktion war „42“.
// (Beachten Sie, dass es für diese spezifische Aussage keinen Zuckerhelfer gibt)
erwarten(MockFunc.verspotten.Anrufe[MockFunc.verspotten.Anrufe.Länge - 1][0]).sein(42);

// Ein Snapshot prüft, ob ein Mock gleich oft aufgerufen wurde,
// in der gleichen Reihenfolge, mit den gleichen Argumenten. Es wird auch auf den Namen hingewiesen.
erwarten(MockFunc.verspotten.Anrufe).gleich([[arg1,arg2]]);
erwarten(MockFunc.getMockName()).sein(„ein Scheinname“);

Eine vollständige Liste der Matcher finden Sie unterReferenzdokumente.

References

Top Articles
Latest Posts
Article information

Author: Neely Ledner

Last Updated: 08/29/2023

Views: 5989

Rating: 4.1 / 5 (62 voted)

Reviews: 93% of readers found this page helpful

Author information

Name: Neely Ledner

Birthday: 1998-06-09

Address: 443 Barrows Terrace, New Jodyberg, CO 57462-5329

Phone: +2433516856029

Job: Central Legal Facilitator

Hobby: Backpacking, Jogging, Magic, Driving, Macrame, Embroidery, Foraging

Introduction: My name is Neely Ledner, I am a bright, determined, beautiful, adventurous, adventurous, spotless, calm person who loves writing and wants to share my knowledge and understanding with you.