Bei der nächsten Überprüfung einer dicken Pull-Anfrage stieß ich auf Unit-Tests mit falscher Benennung von Testfällen. Die Diskussion des Wortlauts in den Testfällen verlief ähnlich wie das Gespräch zwischen Yanychar und Legkostupov im Film "72 Meter" ("wenn es in der Schule so verständlich wäre ..."). Das Gespräch ließ den Gedanken aufkommen, dass es in russischsprachigen Ressourcen schwierig ist, einen erklärenden Leitfaden genau anhand von Textformulierungen zu finden. Ich habe mich entschlossen, mich auf Russisch zu suchen (normalerweise verwende ich nur englischsprachige Quellen). Auf einem Habr wurden mehrere Handbücher zu Unit-Tests gefunden, die jedoch alle Details von Formulierungen in Testfällen umgehen. Unter dem Schnitt mein Versuch, diese Lücke zu füllen.
Disclamer
Es besteht die Möglichkeit, dass ich schlecht aussehe / zu diagonal lese. Hier ist ein Beispiel dafür, wie das Thema dieses Artikels in den Artikeln behandelt wird, die mir aufgefallen sind.

TDD für Anfänger
Auf Wunsch von Kollegen, die nicht gerne englische Handbücher lesen, habe ich beschlossen, englischsprachige Handbücher zu übersetzen und zusammenzustellen.
Vom Übersetzer
Ich habe diese beiden Materialien als Grundlage für den Artikel genommen:
Ich muss auch beachten, dass ich in einigen Testbeispielen eine teilweise Übersetzung ins Russische machen musste. Der Wortlaut in den "beschreiben" -Blöcken bleibt absichtlich in englischer Sprache, wie Mit hoher Wahrscheinlichkeit enthalten sie den Namen von Funktionen, JS-Modulen oder anderen Entitäten im Code, aber in den "it" -Blöcken ist der Text bereits zur besseren Lesbarkeit übersetzt.
Meine persönliche Präferenz ist, dass alles im Code auf Englisch sein sollte.
Benennungstests
Der Name des Tests sollte seinen Zweck so kurz und explizit wie möglich beschreiben. Der Name und die Beschreibung des Tests sollten als erstes die Ursache der Fehlfunktion angeben. Das Testergebnis in der Konsole sollte grammatikalisch korrekt gelesen werden. Entwickler von Drittanbietern sollten keine Rätsel in ihren Köpfen lösen und versuchen zu erraten, woran der Autor des Tests dachte. Tests sind Teil der Dokumentation für das Programm und müssen auch korrekt geschrieben sein.
SCHLECHTES Beispiel:
describe('discoveryService => initDiscoveries', () => { it(' discoveries ( , ..)', () => {
Aus den obigen Beispielen ist schwer zu verstehen, welche spezifischen Maßnahmen ausgeführt werden und zu welchem konkreten Ergebnis die Maßnahme führen sollte.
GUTES Beispiel:
describe('discoveryService => initDiscoveries', () => { it(' discoveries', () => {
Hinweis perev. # 1: Beachten Sie, dass der Textblock darin mit einem Großbuchstaben wie beginnt ist eine Fortsetzung des Satzes, der in der Beschreibung begann.
Hinweis perev. # 2: In den obigen Beispielen wird "DiscoveryService => initDiscoveries" dennoch korrekter in zwei Descibe- Blöcke aufgeteilt (einer ist im anderen verschachtelt).
Hinweis perev. # 3: Beachten Sie, dass in den obigen Beispielen zur Entdeckung kein zweiter Teil der Testfallbeschreibung vorhanden ist. es impliziert einen Text der Form "bei seiner Anrufung", der vom Standpunkt der Manifestation nicht sehr gut ist; In einfachen Fällen ist das Kopieren und Einfügen "wenn es aufgerufen wird" meiner Meinung nach nicht besonders rentabel.
Im Beschreibungsblock wird normalerweise eine Beschreibung der Elementararbeit (Unit of Work, UoW) platziert. Der Wortlaut im it- Block sollte mit dem Muster " Arbeitseinheit - Szenario / Kontext - erwartetes Verhalten " fortgesetzt werden, das in Beschreibung begann:
[ ] [ / ] ( | ) [ ]
oder als Code:
describe('[unit of work]', () => { it(' [ ] / [/]', () => { }); });
Wenn mehrere Testgruppen demselben Skript folgen oder in denselben Kontext passen, können Sie die verschachtelten Blöcke beschreiben verwenden.
describe('[unit of work]', () => { describe('// [scenario/context]', () => { it('/ [expected behaviour]', () => { }); }); }); describe(' Gallery', () => { describe(' ', () => { it(' ', () => { }); it(' ', () => { }); });
EIN TEST - EIN PROBLEM
Jeder Test sollte sich auf ein bestimmtes Szenario in der Anwendung konzentrieren. Der Test, der für einen bestimmten Aspekt verantwortlich ist, kann die spezifische Ursache der Fehlfunktion identifizieren. Je spezifischer der Test ist, desto weniger wahrscheinlich ist es, dass es mehrere Gründe für das falsche Verhalten gibt. Versuchen Sie, nur einen Expect- Block in einem It- Block zu platzieren.
SCHLECHTES Beispiel:
describe('isUndefined function', ()=> { it(' true or false undefined', () => { expect(isUndefined(undefined)).toEqual(true); expect(isUndefined(true)).toEqual(false); }); });
Der it- Block enthält zwei Expect- Blöcke. Dies bedeutet, dass der Entwickler, der ein negatives Ergebnis dieses Tests sieht, nicht genau feststellen kann, was in seinem Code falsch ist und wie er behoben werden kann.
GUTES Beispiel:
describe('isUndefined function', ()=> { it(' true, undefined', () => { expect(isUndefined(undefined)).toEqual(true); }); it(' false ', () => { expect(isUndefined(true)).toEqual(false); }); });
Jeder Test im obigen Beispiel bewertet ein bestimmtes Problem. Darüber hinaus beschreibt die Testbeschreibung klar, in welchem Fall sie bestanden wird. In beiden Fällen liest der Entwickler in der Konsole eine Liste der Ergebnisse ein, die unter welchen Aktionen / Bedingungen von der getesteten Benutzerfunktionalität erwartet werden.
Testverhalten
Schauen Sie sich das Bild an, schauen Sie nicht auf die Striche. Testen Sie benutzerdefinierte Skripte / Verhaltensweisen, nicht Implementierungsdetails. Das Ändern der Implementierungsdetails hat dann keine Auswirkungen auf die Testergebnisse. Ein negatives Testergebnis sollte anzeigen, ob sich das Programm aus Sicht des Benutzers korrekt verhält. Der Test sollte die Implementierungsdetails nicht kontrollieren / einschränken.
SCHLECHTES Beispiel:
it(' discovery ', () => { discoveriesCache.addDiscovery('57463', 'John'); expect(discoveriesCache._discoveries[0].id).toBe('57463'); expect(discoveriesCache._discoveries[0].name).toBe('John'); });
Was ist hier schlecht? Erstens erwarten zwei Blöcke, aber das ist nicht die Hauptsache. Zweitens wird nicht das Verhalten getestet, sondern die Implementierungsdetails. Die Implementierungsdetails ändern sich (private Felder werden umbenannt) - der Test wird ungültig und muss neu geschrieben werden.
GUTES Beispiel:
it(' discovery ', () => { discoveriesCache.addDiscovery('57463', 'John'); expect(discoveriesCache.isDiscoveryExist('57463', 'John')).toBe(true); });
In diesem Beispiel wird eine öffentliche API getestet, die so stabil wie möglich sein sollte.
SCHLUSSFOLGERUNG EINES ÜBERSETZERS
"Onegin war ein Pedant ..." Ich habe den Eindruck, dass die meisten Entwickler der Genauigkeit und Lesbarkeit von Testnamen wenig Aufmerksamkeit schenken. Oft beobachte ich ziemlich lange Diskussionen wie "Was macht dieser Code?" Oder "Warum dieser Code?". Dies gilt sowohl für den Hauptcode in JS (unklare, unscharfe Namen von Modulen, Diensten, Funktionen und Variablen) als auch für Tests (verschwommene Fälle, Testimplementierungsdetails, unscharfe Beschreibungen). All dies führt dazu, dass der Code nicht ganz den Erwartungen entspricht.
In einem seiner Interviews sagte David Heinemeier Hansson (Erfinder des Rails-Frameworks) Folgendes:
"Unit-Tests zeigen nur, dass Ihr Programm das erwartete%% o ausführt."
Er meinte, dass das Verhalten getestet werden sollte, nicht die Codeeinheiten. Und die Textsprache sollte ein Verhaltensmuster haben. Das heißt, "Entität A muss sich unter diesen und jenen Bedingungen so und so verhalten." Eine Kette der Form beschreiben [- beschreiben ] - es - erwarten - sollte sich in eine solche Faltformulierung verwandeln.
Vielen Dank für Ihre Aufmerksamkeit!