Testen von Komponenten im Winkel mit Jasmin Teil 1

Was Sie erstellen werden

Test Driven Development ist eine Programmierpraxis, die von jeder Entwicklergemeinschaft der Erde gepredigt und gefördert wird. Dies ist jedoch eine Routine, die von Entwicklern weitgehend vernachlässigt wird, während sie ein neues Framework erlernen. Das Schreiben von Komponententests vom ersten Tag an hilft Ihnen, besseren Code zu schreiben, Fehler leicht zu erkennen und einen besseren Entwicklungsworkflow zu gewährleisten.

Testgetriebene Entwicklung in Angular

Als vollwertige Front-End-Entwicklungsplattform verfügt Angular über eigene Tools zum Testen. In diesem Tutorial werden wir die folgenden Tools verwenden:

  • Jasmine Framework. Jasmine ist ein beliebtes verhaltensorientiertes Testframework für JavaScript. Mit Jasmine können Sie Tests schreiben, die ausdrucksvoller und unkomplizierter sind. Hier ist ein Beispiel zum Einstieg. 
 it ('sollte eine definierte Komponente haben', () => expect (Komponente) .toBeDefined (););
  • Karma Test Runner. Karma ist ein Tool, mit dem Sie Ihre Anwendung auf mehreren Browsern testen können. Karma bietet Plugins für Browser wie Chrome, Firefox, Safari und viele andere. Ich bevorzuge es jedoch, zum Testen einen Headless-Browser zu verwenden. Einem headless-Browser fehlt eine grafische Benutzeroberfläche. Auf diese Weise können Sie die Testergebnisse in Ihrem Terminal speichern. In diesem Lernprogramm konfigurieren wir Karma für die Verwendung mit Chrome und optional mit einer Headless-Version von Chrome.
  • Angular Testing-Dienstprogramme. Angular Testing-Dienstprogramme bieten Ihnen eine Bibliothek zum Erstellen einer Testumgebung für Ihre Anwendung. Klassen wie TestBed und ComponentFixtures und Hilfsfunktionen wie asynchron und fakeAsync sind Teil der @ Winkel / Kern / Prüfung Paket. Sie müssen sich mit diesen Dienstprogrammen vertraut machen, wenn Sie Tests schreiben möchten, die zeigen, wie Ihre Komponenten mit ihrer eigenen Vorlage, ihren eigenen Diensten und anderen Komponenten interagieren.

In diesem Tutorial werden keine Funktionstests mit Protractor behandelt. Protractor ist ein beliebtes End-to-End-Test-Framework, das mit der Benutzeroberfläche der Anwendung über einen tatsächlichen Browser interagiert. 

In diesem Lernprogramm befassen wir uns mehr mit dem Testen von Komponenten und deren Logik. Wir werden jedoch einige Tests schreiben, in denen die grundlegende Interaktion der Benutzeroberfläche mit dem Jasmine-Framework veranschaulicht wird.

Unser Ziel

Das Ziel dieses Lernprogramms besteht darin, das Frontend für eine Pastebin-Anwendung in einer testgetriebenen Entwicklungsumgebung zu erstellen. In diesem Tutorial folgen wir dem beliebten TDD-Mantra, das "Rot / Grün / Refaktor" ist. Wir schreiben Tests, die anfangs fehlschlagen (rot), und arbeiten dann an unserem Anwendungscode, damit sie bestanden werden (grün). Wir werden unseren Code umgestalten, wenn er zu stinken beginnt, was bedeutet, dass er aufgebläht und hässlich wird.  

Wir werden Tests für Komponenten, ihre Vorlagen, Services und die Pastebin-Klasse schreiben. Das Bild unten zeigt die Struktur unserer Pastebin-Anwendung. Die ausgegrauten Elemente werden im zweiten Teil des Tutorials erläutert. 

Im ersten Teil der Serie konzentrieren wir uns ausschließlich auf die Einrichtung der Testumgebung und die Erstellung grundlegender Tests für Komponenten. Angular ist ein komponentenbasiertes Framework. Daher ist es eine gute Idee, einige Zeit mit dem Schreiben von Tests für Komponenten zu verbringen. Im zweiten Teil der Serie werden komplexere Tests für Komponenten, Komponenten mit Eingängen, geroutete Komponenten und Dienste geschrieben. Am Ende der Serie werden wir eine voll funktionsfähige Pastebin-Anwendung haben, die so aussieht.

Ansicht der Pastebin-KomponenteAnsicht der AddPaste-Komponente
Ansicht der ViewPaste-Komponente

In diesem Tutorial lernen Sie, wie Sie:

  • Konfigurieren Sie Jasmine und Karma
  • Erstellen Sie eine Pastebin-Klasse, die eine einzelne Paste darstellt
  • Erstellen Sie einen einfachen PastebinService 
  • Erstellen Sie zwei Komponenten, Pastebin und AddPaste
  • Schreiben Sie Unit-Tests

Der gesamte Code für das Tutorial ist auf Github verfügbar. 

https://github.com/blizzerand/pastebin-angular

Klonen Sie das Repo und schauen Sie sich den Code an, wenn Sie zu irgendeinem Zeitpunkt in dieser Anleitung Zweifel haben. Lass uns anfangen!

Konfigurieren von Jasmin und Karma

Die Entwickler von Angular haben es uns leicht gemacht, unsere Testumgebung einzurichten. Um zu beginnen, müssen wir zuerst Angular installieren. Ich bevorzuge die Angular-CLI. Es handelt sich um eine All-in-One-Lösung, die das Erstellen, Generieren, Erstellen und Testen Ihres Angular-Projekts übernimmt.

ng neues Pastebin

Hier ist die Verzeichnisstruktur, die von Angular-CLI erstellt wurde. 

Da sich unsere Interessen eher auf die Testaspekte in Angular beziehen, müssen wir nach zwei Arten von Dateien Ausschau halten.

karma.conf.js ist die Konfigurationsdatei für den Karma-Testläufer und die einzige Konfigurationsdatei, die wir zum Schreiben von Unit-Tests in Angular benötigen. Standardmäßig ist Chrome das Standard-Startprogramm, mit dem Karma Tests erfasst. Wir erstellen ein benutzerdefiniertes Startprogramm für die Ausführung des headless Chrome und fügen es dem hinzu Browser Array.

/*karma.conf.js*/ browser: ['Chrome', 'ChromeNoSandboxHeadless'], customLaunchers: ChromeNoSandboxHeadless: Basis: 'Chrome', Flags: ['--no-sandbox', // Siehe https: / /chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md '--headless', '--disable-gpu', // Google Chrome wird ohne Remote-Debug-Port sofort beendet. '--remote-debugging-port = 9222',],,,

Die andere Art von Datei, nach der wir Ausschau halten müssen, ist alles, was endet .spez.ts. Per Konvention werden die in Jasmine geschriebenen Tests als Specs bezeichnet. Alle Testspezifikationen sollten sich innerhalb der Anwendung befinden src / app / Verzeichnis, weil Karma dort nach den Testspezifikationen sucht. Wenn Sie eine neue Komponente oder einen neuen Dienst erstellen, müssen Sie Ihre Testspezifikationen in demselben Verzeichnis ablegen, in dem sich der Code für die Komponente oder den Dienst befindet. 

Das ng neu Befehl hat ein erstellt app.component.spec.ts Datei für unsere app.component.ts. Öffnen Sie es und werfen Sie einen Blick auf die Jasmin-Tests in Angular. Auch wenn der Code keinen Sinn ergibt, ist das in Ordnung. Wir behalten AppComponent für den Moment bei und hosten die Routen zu einem späteren Zeitpunkt im Tutorial. 

Die Pastebin-Klasse erstellen

Wir benötigen eine Pastebin-Klasse, um unser Pastebin in den Komponenten und Tests zu modellieren. Sie können eine mit der Angular-CLI erstellen.

ng generiere Klasse Pastebin

Fügen Sie die folgende Logik zu Pastebin.ts hinzu:

Exportklasse Pastebin ID: Nummer; Titel: String; Sprache: String; einfügen: string; Konstruktor (Werte: Object = ) Object.assign (this, values);  export const Languages ​​= ["Ruby", "Java", "JavaScript", "C", "Cpp"]; 

Wir haben eine Pastebin-Klasse definiert, und jede Instanz dieser Klasse hat die folgenden Eigenschaften:

  • Ich würde 
  • Titel
  • Sprache
  • Einfügen

Erstellen Sie eine weitere Datei namens pastebin.spec.ts für die Testsuite. 

/ * pastebin.spec.ts * / // importiere die Pastebin-Klasse import Pastebin aus './pastebin'; beschreiben ('Pastebin', () => it ('sollte eine Instanz von Pastebin erstellen', () => expect (neues Pastebin ()). toBeTruthy (););)

Die Testsuite beginnt mit einem beschreiben block, eine globale Jasmine-Funktion, die zwei Parameter akzeptiert. Der erste Parameter ist der Titel der Testsuite, und der zweite ist die tatsächliche Implementierung. Die Spezifikationen werden mit einem definiert es Funktion, die zwei Parameter annimmt, ähnlich wie bei der beschreiben Block. 

Mehrere Spezifikationen (es Blöcke) können innerhalb einer Testsuite verschachtelt werden (beschreiben Block). Stellen Sie jedoch sicher, dass die Titel der Testsuite so benannt sind, dass sie eindeutig und lesbarer sind, da sie dem Leser als Dokumentation dienen sollen. 

Erwartungen, umgesetzt mit der erwarten von Funktion, werden von Jasmine verwendet, um zu bestimmen, ob eine Spezifikation erfolgreich ist oder nicht. Das erwarten von Funktion nimmt einen Parameter an, der als Istwert bezeichnet wird. Es wird dann mit einer anderen Funktion verkettet, die den erwarteten Wert annimmt. Diese Funktionen werden Matcher-Funktionen genannt, und wir werden die Matcher-Funktionen wie verwenden toBeTruthy ()zu definieren()sein(), und enthalten() viel in diesem Tutorial. 

 erwarten (new Pastebin ()). toBeTruthy ();

Mit diesem Code haben wir also eine neue Instanz der Pastebin-Klasse erstellt und erwarten, dass sie wahr ist. Fügen Sie eine weitere Spezifikation hinzu, um zu bestätigen, dass das Pastebin-Modell wie beabsichtigt funktioniert. 

it ('soll Werte annehmen', () => let pastebin = new Pastebin (); pastebin = id: 111, titel: "Hello world", sprache: "Ruby", einfügen: 'print "Hello"',  erwarten (pastebin.id) .toEqual (111); erwarten (pastebin.language) .toEqual ("Ruby"); erwarten (pastebin.paste) .toEqual ('print "Hello"');); 

Wir haben die Pastebin-Klasse instanziiert und unserer Testspezifikation ein paar Erwartungen hinzugefügt. Lauf ng test um zu überprüfen, ob alle Tests grün sind.

Bare-Bones-Service erstellen

Generieren Sie einen Dienst mit dem folgenden Befehl.

ng Dienst Pastebin generieren

PastebinService hosten die Logik zum Senden von HTTP-Anforderungen an den Server; Wir haben jedoch keine Server-API für die von uns erstellte Anwendung. Daher simulieren wir die Serverkommunikation mit einem Modul namens InMemoryWebApiModule. 

Einrichten der Angular-in-Memory-Web-API

Installieren wink-in-memory-web-api über npm:

npm installiert angle-in-memory-web-api --save

Aktualisieren Sie AppModule mit dieser Version.

/ * app.module.ts * / import BrowserModule aus '@ angle / platform-browser'; NgModule aus '@ angle / core' importieren; // Komponenten importieren AppComponent aus './app.component'; // Dienst für Pastebin import PastebinService aus "./pastebin.service"; // In diesem Tutorial verwendete Module importieren HttpModule von '@ angle / http'; // Im Arbeitsspeicher Web-API, um einen http-Server zu simulieren InMemoryWebApiModule von 'angle-in-memory-web-api'; import InMemoryDataService von './in-memory-data.service'; @NgModule (Deklarationen: [AppComponent]] importiert: [BrowserModule, HttpModule, InMemoryWebApiModule.forRoot (InMemoryDataService)], Anbieter: [PastebinService], Bootstrap: [AppComponent]) Exportklasse AppModule  

Erstelle ein InMemoryDataService das implementiert InMemoryDbService

/*in-memory-data.service.ts*/ import InMemoryDbService aus 'angle-in-memory-web-api'; importieren Sie Pastebin aus './pastebin'; Exportklasse InMemoryDataService implementiert InMemoryDbService createDb () const pastebin: Pastebin [] = [id: 0, Titel: "Hello world Ruby", Sprache: "Ruby", Einfügen: 'setzt "Hello World"', id : 1, Titel: "Hallo Welt C", Sprache: "C", Einfügen: 'printf ("Hallo Welt");', id: 2, Titel: "Hallo Welt CPP", Sprache: "C ++", einfügen: 'cout<<"Hello world";', id: 3, title: "Hello world Javascript", language: "JavaScript", paste: 'console.log("Hello world")' ]; return pastebin;  

Hier, Pastebin ist ein Array von Musterpasten, das zurückgegeben oder aktualisiert wird, wenn wir eine HTTP-Aktion wie ausführen http.get oder http.post.  

/*pastebin.service.ts * / import Injectable from '@ angle / core'; importieren Sie Pastebin aus './pastebin'; Http, Header aus '@ angle / http' importieren; import 'rxjs / add / operator / toPromise'; @Injectable () - Exportklasse PastebinService // Das Projekt verwendet InMemoryWebApi zur Verarbeitung der Server-API. // Hier simuliert "api / pastebin" eine Server-API-URL private pastebinUrl = "api / pastebin"; private Header = neue Header ('Content-Type': "application / json"); Konstruktor (private http: Http)  // getPastebin () führt http.get () aus und gibt ein öffentliches Versprechen aus. getPastebin (): Promise return this.http.get (this.pastebinUrl) .toPromise () .then (response => response.json (). data) .catch (this.handleError);  private handleError (Fehler: beliebig): Versprechen console.error ('Ein Fehler ist aufgetreten', Fehler); return Promise.reject (error.message || error); 

Das getPastebin () Die Methode stellt eine HTTP.get-Anforderung und gibt ein Versprechen zurück, das in ein Array von vom Server zurückgegebenen Pastebin-Objekten aufgelöst wird.

Wenn Sie eine bekommen Kein Anbieter für HTTP Error Während Sie eine Spezifikation ausführen, müssen Sie das HTTPModule in die betreffende Spezifikationsdatei importieren. 

Erste Schritte mit Komponenten

Komponenten sind der grundlegendste Baustein einer Benutzeroberfläche in einer Angular-Anwendung. Eine Angular-Anwendung ist ein Baum aus Angular-Komponenten. 
- Winkeldokumentation

Wie zuvor im Abschnitt Übersicht hervorgehoben, werden wir in diesem Lernprogramm an zwei Komponenten arbeiten: PastebinComponent und AddPasteComponent. Die Pastebin-Komponente besteht aus einer Tabellenstruktur, in der alle vom Server abgerufenen Einfügungen aufgeführt sind. Die AddPaste-Komponente enthält die Logik zum Erstellen neuer Pasten.   

Entwerfen und Testen der Pastebin-Komponente

Fahren Sie fort und generieren Sie die Komponenten mithilfe von Angular-CLI. 

ng g-Komponente --spec = false Pastebin

Das --spec = falsch Diese Option weist die Angular-CLI an, keine Spezifikationsdatei zu erstellen. Dies liegt daran, dass wir Komponententests von Grund auf neu schreiben wollen. Ein ... kreieren pastebin.component.spec.ts Datei in der Pastebin-Komponente Mappe.

Hier ist der Code für pastebin.component.spec.ts.

import TestBed, ComponentFixture, async aus '@ angle / core / testing'; importiere DebugElement von '@ angle / core'; import PastebinComponent aus './pastebin.component'; By aus '@ angle / platform-browser' importieren; importieren Sie Pastebin, Languages aus '… / Pastebin'; // Module zum Testen des Imports HttpModule von '@ angle / http'; beschreiben ('PastebinComponent', () => // TypScript-Deklarationen. Lassen Sie comp: PastebinComponent; lassen Sie das Fixture: ComponentFixture; let de: DebugElement; let element: HTMLElement; let mockPaste: Pastebin []; // beforeEach wird einmal vor jedem "it" -Block in einem Test aufgerufen. // Verwenden Sie diese Option zum Konfigurieren der Komponente, zum Injizieren von Diensten usw. beforeEach (()) => TestBed.configureTestingModule (deklarationen: [PastebinComponent], // deklarieren Sie die Testkomponentenimporte: [HttpModule],); fixture = TestBed .createComponent (PastebinComponent); comp = fixture.componentInstance; de ​​= fixture.debugElement.query (By.css ('. pastebin')); element = de.nativeElement;); )

Hier ist viel los. Lass es uns aufteilen und ein Stück nach dem anderen nehmen. Innerhalb des beschreiben block, wir haben einige Variablen deklariert und dann eine vor jedem Funktion. beforeEach () ist eine globale Funktion, die von Jasmine bereitgestellt wird und, wie der Name vermuten lässt, vor jeder Spezifikation in der aufgerufen wird beschreiben Block, in dem es aufgerufen wird. 

TestBed.configureTestingModule (Deklarationen: [PastebinComponent], // Deklarieren der Testkomponentenimporte: [HttpModule],);

TestBed class ist ein Teil der Angular-Testprogramme und erstellt ein Testmodul, das dem von @NgModule Klasse. Außerdem können Sie konfigurieren TestBed Verwendung der configureTestingModule Methode. Sie können beispielsweise eine Testumgebung für Ihr Projekt erstellen, die die eigentliche Angular-Anwendung emuliert, und Sie können dann eine Komponente aus Ihrem Anwendungsmodul ziehen und sie erneut an dieses Testmodul anschließen. 


fixture = TestBed.createComponent (PastebinComponent); comp = fixture.componentInstance; de = fixture.debugElement.query (By.css ('div')); element = de.nativeElement;

Aus der Angular-Dokumentation:

Das createComponent Methode gibt a zurück ComponentFixture, Ein Handle für die Testumgebung, die die erstellte Komponente umgibt. Das Fixture bietet Zugriff auf die Komponenteninstanz selbst und auf die DebugElement, Dies ist ein Handle für das DOM-Element der Komponente.

Wie bereits erwähnt, haben wir ein Fixture von der erstellt PastebinComponent und dann mit diesem Gerät eine Instanz der Komponente erstellt. Wir können jetzt durch Aufruf auf die Eigenschaften und Methoden der Komponente in unseren Tests zugreifen comp.property_name. Da bietet das Gerät auch Zugriff auf die debugElement, Wir können jetzt die DOM-Elemente und Selektoren abfragen. 

Es gibt ein Problem mit unserem Code, an das wir noch nicht gedacht haben. Unsere Komponente verfügt über eine externe Vorlage und eine CSS-Datei. Das Abrufen und Lesen aus dem Dateisystem ist eine asynchrone Aktivität, im Gegensatz zum restlichen Code, der alles synchron ist. 

Angular bietet Ihnen eine aufgerufene Funktion async () das kümmert sich um alles asynchrone Zeug. Was asynchron ist, ist, alle asynchronen Aufgaben darin zu verfolgen und uns die Komplexität der asynchronen Ausführung zu verbergen. Wir haben jetzt zwei beforeEach-Funktionen, eine asynchrone beforeEach () und ein synchrones beforeEach ().

/ * pastebin.component.spec.ts * / // beforeEach wird vor jedem "it" -Block eines Tests einmal aufgerufen. // Verwenden Sie diese Option zum Konfigurieren der Komponente, zum Injizieren von Diensten usw. beforeEach (async (()) => // async before wird zum Kompilieren externer Vorlagen verwendet. Dies ist eine asynchrone Aktivität. TestBed.configureTestingModule (deklarationen: [PastebinComponent], / / deklariere die Importe der Testkomponente: [HttpModule],) .compileComponents (); // Kompiliervorlage und css)); beforeEach (() => // Und hier ist die synchrone async-Funktion fixture = TestBed.createComponent (PastebinComponent); comp = fixture.componentInstance; de ​​= fixture.debugElement.query (By.css ('. pastebin'); element = de.nativeElement;); 

Wir haben noch keine Testspezifikationen geschrieben. Es ist jedoch eine gute Idee, vorher einen Überblick über die Spezifikationen zu erstellen. Das Bild unten zeigt ein grobes Design der Pastebin-Komponente.

Wir müssen Tests mit den folgenden Erwartungen schreiben.

  • Die Pastebin-Komponente sollte vorhanden sein.
  • Die title -Eigenschaft der Komponente sollte in der Vorlage angezeigt werden.
  • Die Vorlage sollte über eine HTML-Tabelle verfügen, um die vorhandenen Pasten anzuzeigen.
  • PastebinService wird in die Komponente eingespritzt, und ihre Methoden sind zugänglich.
  • Es sollten keine Pasten angezeigt werden onInit () wird genannt.
  • Pasten werden erst angezeigt, nachdem das Versprechen in unserem Service gelöst wurde.

Die ersten drei Tests sind einfach zu implementieren. 

 it ('sollte eine Komponente haben', () => expect (comp) .toBeTruthy ();); it ('sollte einen Titel haben', () => comp.title = 'Pastebin-Anwendung'; fixture.detectChanges (); expect (element.textContent) .toContain (comp.title);) sollte es (') haben eine Tabelle zur Anzeige der Pasten ', () => expect (element.innerHTML) .toContain ("thead"); Expect (element.innerHTML) .toContain ("tbody");) 

In einer Testumgebung bindet Angular die Eigenschaften der Komponente nicht automatisch mit den Vorlagenelementen. Sie müssen explizit anrufen fixture.detectChanges () jedes Mal, wenn Sie eine Komponenteneigenschaft mit der Vorlage verbinden möchten. Beim Ausführen des Tests sollte ein Fehler angezeigt werden, da die Titeleigenschaft in unserer Komponente noch nicht deklariert wurde.

 title: string = "Pastebin-Anwendung";

Vergessen Sie nicht, die Vorlage mit einer grundlegenden Tabellenstruktur zu aktualisieren.

Titel

Ich würde Titel Sprache Code

Für den Rest der Fälle müssen wir das injizieren Pastebinservice Schreiben Sie Tests, die sich mit der Interaktion zwischen Komponenten und Diensten befassen. Ein echter Dienst kann Anrufe an einen Remote-Server tätigen, und das Einfügen dieses Dienstes in seiner Rohform ist eine mühsame und herausfordernde Aufgabe. 

Stattdessen sollten wir Tests schreiben, die sich darauf konzentrieren, ob die Komponente erwartungsgemäß mit dem Dienst interagiert. Wir werden Daten hinzufügen, die der Spion auf der PastebinService und sein getPastebin () Methode.

Importieren Sie zuerst die PastebinService in unsere Testsuite.

importieren Sie PastebinService aus '… /pastebin.service';

Als nächstes fügen Sie es dem hinzu Anbieter Array im Inneren TestBed.configureTestingModule ().

TestBed.configureTestingModule (Deklarationen: [CreateSnippetComponent], Anbieter: [PastebinService],);

Mit dem nachstehenden Code wird ein Jasmin-Spion erstellt, der alle Anrufe an die verfolgen soll getPastebin () Methode und geben Sie ein Versprechen zurück, das sofort aufgelöst wird mockPaste.

// Der echte PastebinService wird in die Komponente injiziert. Let pastebinService = fixture.debugElement.injector.get (PastebinService); mockPaste = [id: 1, Titel: "Hallo Welt", Sprache: "Ruby", Einfügen: "setzt" Hallo ""]; spy = spyOn (pastebinService, 'getPastebin') .und.returnValue (Promise.resolve (mockPaste));

Der Spion kümmert sich nicht um die Implementierungsdetails des realen Dienstes, sondern umgeht stattdessen jeden Aufruf zum tatsächlichen Dienst getPastebin () Methode. Außerdem sind alle Fernanrufe im Inneren vergraben getPastebin () werden von unseren Tests ignoriert. Im zweiten Teil des Tutorials werden isolierte Unit-Tests für Angular-Services geschrieben.

Fügen Sie die folgenden Tests hinzu pastebin.component.spec.ts.

 it ('sollte den Pastebin nicht vor OnInit anzeigen'), () => this.tbody = element.querySelector ("tbody"); // Versuchen Sie es ohne die 'replace (\ s \ s + / g,') - Methode und sehen, was passiert, erwartet (this.tbody.innerText.replace (/ \ s \ s + / g, ")). toBe (" "," tbody soll leer sein "); erwartet (spy.calls.any ()). toBe (false, "Spy sollte noch nicht gerufen werden");); it ('sollte Pastebin nach initialisierter Komponente immer noch nicht anzeigen'), () => fixture.detectChanges (); // Der getPastebin-Dienst ist async, aber der Test ist nicht erwartet (this.tbody.innerText.replace (/ \ s \ s + / g, ")). toBe (" ", 'tobody soll noch leer'); erwarten Sie (spy.calls.any ()). toBe (true, 'getPastebin sollte aufgerufen werden');); ('sollte das Pastebin anzeigen, nachdem getPastebin versprechen aufgelöst wurde', async () => fixture.detectChanges (); fixture.whenStable (). then (() => fixture.detectChanges (); erwarten Sie (comp.pastebin). toEqual (jasmine.objectContaining (mockPaste)); erwarten (element.innerText.replace (/ \ s \ s + / g, ")). toContain (mockPaste [0] .title););)

Die ersten beiden Tests sind Synchrontests. Die erste Spezifikation prüft, ob die innerText des div Das Element bleibt leer, solange die Komponente nicht initialisiert wird. Das zweite Argument von Jasmines Matcher-Funktion ist optional und wird angezeigt, wenn der Test fehlschlägt. Dies ist hilfreich, wenn Sie mehrere Expect-Anweisungen in einer Spezifikation haben.

In der zweiten Spezifikation wird die Komponente initialisiert (weil fixture.detectChanges () wird aufgerufen), und es wird auch erwartet, dass der Spion aufgerufen wird, die Vorlage sollte jedoch nicht aktualisiert werden. Obwohl der Spion ein gelöstes Versprechen zurückgibt, wird der mockPaste ist noch nicht verfügbar. Es sollte nur verfügbar sein, wenn der Test ein asynchroner Test ist.

Der dritte Test verwendet eine async () Funktion, die zuvor beschrieben wurde, um den Test in einer asynchronen Testzone auszuführen. async () wird verwendet, um einen synchronen Test asynchron zu machen. fixture.whenStable () wird aufgerufen, wenn alle anstehenden asynchronen Aktivitäten ergänzt werden, und dann eine zweite Runde fixture.detectChanges () wird aufgerufen, um das DOM mit den neuen Werten zu aktualisieren. Die Erwartung im letzten Test stellt sicher, dass unser DOM mit dem aktualisiert wird mockPaste Werte.

Um die Tests bestehen zu können, müssen wir unsere Version aktualisieren pastebin.component.ts mit dem folgenden Code.

/*pastebin.component.ts*/ import Component, OnInit aus '@ angle / core'; importieren Sie Pastebin aus '… / Pastebin'; importieren Sie PastebinService aus '… /pastebin.service'; @Component (Selector: 'app-pastebin', templateUrl: './pastebin.component.html', styleUrls: ['./pastebin.component.css']) export-Klasse PastebinComponent implementiert OnInit title: string = " Pastebin-Anwendung "; Pastebin: any = []; Konstruktor (public pastebinServ: PastebinService)  // loadPastebin () wird bei init aufgerufen ngOnInit () this.loadPastebin ();  public loadPastebin () // ruft die Methode getPastebin () von pastebin service auf und speichert die Antwort in der Eigenschaft 'pastebin' this.pastebinServ.getPastebin (). then (pastebin => this.pastebin = pastebin);  

Die Vorlage muss auch aktualisiert werden.

 

Titel

Ich würde Titel Sprache Code
paste.id paste.title paste.language Code anzeigen

Eine neue Einfügung hinzufügen

Generieren Sie eine AddPaste-Komponente mit Angular-CLI. Die Abbildung unten zeigt das Design der AddPaste-Komponente.


Die Logik der Komponente sollte die folgenden Spezifikationen erfüllen.

  • Die Vorlage der AddPaste-Komponente sollte über eine Schaltfläche verfügen Einfügen erstellen.
  • Klicken Sie auf die Einfügen erstellen Schaltfläche sollte eine modale Box mit der ID 'source-modal' anzeigen.
  • Die Klick-Aktion sollte auch die Komponente aktualisieren showModal Eigentum an wahr. (showModal ist eine boolesche Eigenschaft, die wahr wird, wenn das Modal angezeigt wird, und falsch, wenn das Modal geschlossen wird.)
  • Drücken Sie die sparen Die Schaltfläche sollte den Pastebin-Dienst aufrufen addPaste () Methode.
  • Klicken Sie auf die schließen Die Schaltfläche sollte die ID 'source-modal' aus dem DOM entfernen und die showModal Eigentum an falsch.

Wir haben die ersten drei Tests für Sie ausgearbeitet. Prüfen Sie, ob Sie die Tests selbst bestehen können. 

beschreiben ('AddPasteComponent', () => lassen Sie Komponente: AddPasteComponent; lassen Sie Fixture: ComponentFixture; let de: DebugElement; let element: HTMLElement; lassen Sie Spion: Jasmin.Spy; let pastebinService: PastebinService; beforeEach (async (()) => TestBed.configureTestingModule (Deklarationen: [AddPasteComponent]) importiert: [HttpModule, FormsModule], Provider: [PastebinService],) .compileComponents ();)); beforeEach (() => // Initialisierung Fixture = TestBed.createComponent (AddPasteComponent); PastebinService = Fixture.debugElement.injector.get (PastebinService); Komponente = Fixture.componentInstance; de ​​= Fixture.debugElement.query (By.css ( '.add-paste')); element = de.nativeElement; spy = spyOn (pastebinService, 'addPaste'). und.callThrough (); // fragen das Fixture nach Änderungen fest. fixture.detectChanges ();; it ('sollte erstellt werden') () => expect (Komponente) .toBeTruthy ();); it ('sollte die' create paste'-Schaltfläche anzeigen ', () => // Es sollte eine create-Schaltfläche in der Vorlage erwartet werden (element.innerText) .toContain ("create paste");); it ('sollte das Modal nur anzeigen, wenn auf die Schaltfläche geklickt wird', () => // source-model ist eine ID für das Modal. Es sollte nicht angezeigt werden, wenn nicht auf die Schaltfläche "create" geklickt wird (element.innerHTML). not.toContain ("source-modal");) it ("sollte das Modal anzeigen, wenn auf" Einfügen erstellen "geklickt wird", () => lassen Sie createPasteButton = fixture.debugElement.query (By.css ("button" )); // triggerEventHandler simuliert ein Klickereignis für das Schaltflächenobjekt createPasteButton.triggerEventHandler ("click", null); fixture.detectChanges (); expect (element.innerHTML) .toContain ("source-modal"); expect (Komponente) .showModal) .toBeTruthy ("showModal sollte true sein");))

DebugElement.triggerEventHandler () ist das einzige, was hier neu ist. Es wird verwendet, um ein Klickereignis auf dem Schaltflächenelement auszulösen, auf dem es aufgerufen wird. Der zweite Parameter ist das Ereignisobjekt, und wir haben es seit der Komponente leer gelassen klicken() erwartet nicht einen. 

Zusammenfassung

Das war's für den Tag. In diesem ersten Artikel haben wir gelernt:

  • wie man Jasmine und Karma einrichtet und konfiguriert
  • wie man grundlegende Tests für Klassen schreibt
  • wie Sie Komponententests für Komponenten entwerfen und schreiben
  • So erstellen Sie einen Basisdienst
  • wie man Angular-Testprogramme in unserem Projekt verwendet

 Im nächsten Lernprogramm erstellen wir neue Komponenten, schreiben weitere Testkomponenten mit Ein- und Ausgängen, Services und Routen. Bleiben Sie dran für den zweiten Teil der Serie. Teilen Sie Ihre Gedanken durch die Kommentare.