Funktionstests der Yandex Alice-Fähigkeiten auf Node.js.

Alice, starte die Fertigkeit


Fast ein Jahr ist vergangen, seit die Gelegenheit, Ihre Fähigkeiten für Alice, die Sprachassistentin von Yandex, zu entwickeln, erschienen ist. Täglich kommen neue Fähigkeiten in den Katalog , und ihre Gesamtzahl beträgt mehrere hundert. Leider summiert sich die Kommunikation mit einigen Fähigkeiten, um es milde auszudrücken, "nicht zusammen". Die Fertigkeit durchläuft entweder dieselbe Phrase oder ist im Allgemeinen unterbrochen und reagiert nicht.


In diesem Artikel werde ich erwägen, funktionale automatisierte Tests für eine Fertigkeit auf Node.js zu schreiben. Das Vorhandensein solcher Tests ermöglicht es Ihnen, bessere Fähigkeiten zu entwickeln und Vertrauen in deren Leistung zu geben.


Vorhandene Testwerkzeuge


Skill for Alice ist ein Webserver, der auf POST-Anfragen in einem bestimmten Format antworten kann. Momentan gibt es verschiedene Tools, mit denen Sie die Skill-URL übertragen und ihre Funktion überprüfen können:


  • Die offizielle Entwicklerkonsole , in der Sie Ihre Fähigkeiten mit Text testen und Anfragen / Antworten ansehen können
  • Aimylogic Station Simulator, unterstützt Sprache
  • Open-Source-Projekt dialogs.popstas.ru zum lokalen Testen von Fähigkeiten

Die Besonderheit dieser Tools besteht darin, dass sie eine Benutzeroberfläche für manuelle Fähigkeitstests bieten. Ich möchte in den besten Traditionen der kontinuierlichen Integration
Führen Sie den Befehl in der Konsole aus, überprüfen Sie automatisch alle Skripte und laden Sie erst dann die neue Version hoch.


Gleichzeitig möchte ich mich nicht mit Unit-Tests einzelner Skill-Module befassen. Das Anforderungs- / Antwortprotokoll ist in der Dokumentation aufgezeichnet , und auf dieser Ebene ist es besser, es zu testen. Selbst nach dem vollständigen Umschreiben der internen Architektur müssen Sie die Tests nicht ändern. Das heißt, dies sind im Wesentlichen Funktionstests .


Ich habe für eine solche Aufgabe keine fertige Bibliothek für Node.js gefunden, also werden wir unsere eigene schreiben :)



Nehmen Sie das offizielle Skill-Beispiel aus dem Yandex-Repository auf GitHub. Dies ist die Fähigkeit "Papagei", die einfach alles wiederholt, was der Benutzer gesagt hat. Errichtet auf der Basis des Mikro- Frameworks und enthält nur wenige Codezeilen:


// server.js const micro = require('micro'); const {json} = micro; module.exports = micro(async req => { const {request, session, version} = await json(req); return { version, session, response: { text: request.original_utterance || 'Hello!', end_session: false, }, }; }); 

Beim ersten Aufruf erhält die Fertigkeit eine leere Nachricht vom Benutzer (original_utterance) und antwortet mit "Hello!" . In anderen Fällen wird die Nachricht des Benutzers einfach in das Feld response.text kopiert.


Ich habe den ursprünglichen GitHub-Beispielcode in die micro() -Funktion eingeschlossen, damit der Export einen http-Server zurückgibt, den wir in Tests verwenden werden.


Testplan


Um eine solche Fähigkeit mit Tests abzudecken, benötigen Sie Folgendes:


  1. Erhöhen Sie einen erfahrenen Server am lokalen Port
  2. Überprüfen Sie zwei Fälle:
    • Der Benutzer gibt die Fertigkeit ein, die Fertigkeit muss mit "Hallo!" Antworten.
    • Der Benutzer sendet eine Nachricht an die Fertigkeit. Die Fertigkeit muss mit derselben Nachricht antworten
  3. Stoppen Sie den Server mit Geschick und zeigen Sie den Bericht an

Durch die Automatisierung dieser Überprüfungen können Sie sie vor jedem Festschreiben ausführen und sicherstellen, dass nichts beschädigt ist.


Wir werden den Testcode gemäß dem Plan unter Verwendung der Syntax für Mokka schreiben. Angenommen, wir haben bereits eine User , die alles kann, was wir brauchen:


 // test.js const assert = require('assert'); before(done => { //    server.listen(PORT, done); }); it('should get hello on enter', async () => { //     const user = new User(`http://localhost:${PORT}`); //       const response = await user.enter(); //    assert.equal(response.text, 'Hello!'); }); after(done => { //   server.close(done); }); 

Es bleibt die User Klasse zu schreiben und es wird möglich sein, den Test auszuführen.


Virtueller Benutzer


Die Hauptsache, die ein Testbenutzer tun sollte, ist das Senden von POST-Anforderungen an die Skill-URL mit Daten im gewünschten Format. Das Anforderungsformat ist in der Dokumentation beschrieben . Jetzt brauchen wir nicht alle Felder, also habe ich nur das Notwendige gelassen, um den Beispielcode nicht aufzublasen. User mit Kommentaren:


 // user.js const fetch = require('node-fetch'); module.exports = class User { /** *  * @param {String} webhookUrl */ constructor(webhookUrl) { this._webhookUrl = webhookUrl; } /** *     */ async enter() { const headers = { 'Accept': 'application/json', 'Content-Type': 'application/json' }; //    ,  -   const body = this._buildRequest(''); const response = await fetch(this._webhookUrl, { method: 'post', headers, body: JSON.stringify(body), }); const json = await response.json(); return json.response; } /** *        * @param {String} message */ _buildRequest(message) { return { request: { command: message, original_utterance: message, type: 'SimpleUtterance', }, session: { new: true, user_id: 'user-1', session_id: 'session-1' }, version: '1.0' } } }; 

Starten


Zunächst müssen die Benutzer- und Serverklassen in die Testdatei importiert und der Wert des Ports festgelegt werden, an dem der Server ansteigen soll:


 // test.js ... const server = require('./server'); const User = require('./user'); const PORT = 3456; ... 

Installieren Sie alle erforderlichen Abhängigkeiten:


 npm install micro node-fetch mocha 

Und führen Sie den Test aus:


 $ mocha test.js ✓ should get hello on enter 1 passing (34ms) 

Alles ist gut, der Test ist bestanden!


Bevor Sie fortfahren, müssen Sie jedoch sicherstellen, dass der Test wirklich funktioniert. Ersetzen Sie dazu die Antwortfähigkeit "Hallo!" zu "Hallo!" und führen Sie es erneut aus:


 $ mocha test.js 0 passing (487ms) 1 failing 1) should get hello on enter: AssertionError [ERR_ASSERTION]: '!' == 'Hello!' + expected - actual -! +Hello! 

Der Test zeigte einen Fehler - wie es sein sollte.
Nun betrachten wir den ersten Fall mit Sicherheit als abgedeckt.


Wir bringen dem Benutzer die Kommunikation bei


Der zweite Fall bleibt bestehen, wenn der Benutzer eine Nachricht an die Fertigkeit sendet und dieselbe Nachricht zurückerhalten muss. Damit der Benutzer "kommunizieren" kann, habe ich der Benutzerklasse die Methode say(message) hinzugefügt. Ich habe auch ein kleines Refactoring durchgeführt: Ich habe http-Anfragen an eine separate Methode say(message) und diese in enter() und say(message) :


 // user.js const fetch = require('node-fetch'); module.exports = class User { /** *  * @param {String} webhookUrl */ constructor(webhookUrl) { this._webhookUrl = webhookUrl; } /** *     */ async enter() { //    ,  -   const body = this._buildRequest(''); return this._sendRequest(body); } /** *     * @param {String} message */ async say(message) { const body = this._buildRequest(message); return this._sendRequest(body); } /** *  http- * @param {Object} body   */ async _sendRequest(body) { const headers = { 'Accept': 'application/json', 'Content-Type': 'application/json' }; const response = await fetch(this._webhookUrl, { method: 'post', headers, body: JSON.stringify(body), }); const json = await response.json(); return json.response; } // ... }; 

Der Testcode für den zweiten Fall sieht folgendermaßen aus:


 it('should reply the same message', async () => { //   const user = new User(`http://localhost:${PORT}`); //    await user.enter(); //   const response = await user.say('  ?'); //    assert.equal(response.text, '  ?'); }); 

Wir fangen wieder an und sehen, dass beide Tests bestanden haben:


 $ mocha test.js ✓ should get hello on enter ✓ should reply the same message 2 passing (37ms) 

Weitere Schritte


Auf die gleiche Weise können Sie der Fertigkeit komplexere Skripte hinzufügen und diese mit Tests abdecken. Dadurch wird sichergestellt, dass neue Änderungen nicht alt werden.


Die erstellte Testinfrastruktur kann ebenfalls verbessert werden:


  • Ändern Sie die User so, dass die verbleibenden Felder in der Anforderung geändert werden können (aktivieren Sie beispielsweise das Kontrollkästchen, dass der Benutzer keinen Bildschirm hat).
  • Code-Abdeckung verbinden (z. B. nyc )
  • Hängen Sie alle Überprüfungen an Pre-Commit / Pre-Push-Hooks (z. B. mit Husky ).

Ich habe mehrere Fähigkeiten, daher habe ich die Testbenutzerklasse in einem separaten Alice-Tester- Paket zusammengefasst. Vielleicht ist jemand hilfreich.


Ich habe auch den vollständigen Arbeitscode des Beispiels aus dem Artikel auf GitHub veröffentlicht . Sie können das Repository klonen und experimentieren.


Vielen Dank für Ihre Aufmerksamkeit!

Source: https://habr.com/ru/post/de441978/


All Articles