Testen von Node.js-Projekten. Teil 1. Testanatomie und Testtypen

Der Autor des Materials, dessen erster Teil der Übersetzung wir heute veröffentlichen, sagt, dass er als unabhängiger Berater auf Node.js jedes Jahr mehr als 10 Projekte analysiert. Seine Kunden, was durchaus gerechtfertigt ist, bitten ihn, dem Testen besondere Aufmerksamkeit zu widmen. Vor einigen Monaten begann er, sich Notizen über wertvolle Testtechniken und die aufgetretenen Fehler zu machen. Das Ergebnis war Material mit drei Dutzend Testempfehlungen.

Bild

Insbesondere wird der Schwerpunkt auf der Auswahl von Testtypen liegen, die für eine bestimmte Situation geeignet sind, auf ihrem richtigen Design, auf der Bewertung ihrer Wirksamkeit und darauf, wo genau in CI / CD-Ketten Sie sie platzieren müssen. Einige der Beispiele hier werden mit Jest illustriert, andere mit Mocha. Dieses Material konzentriert sich hauptsächlich nicht auf Werkzeuge, sondern auf Testmethoden.

→ Testen von Node.js-Projekten. Teil 2. Bewertung der Testleistung, kontinuierliche Integration und Analyse der Codequalität

â–Ť0. Goldene Regel: Tests sollten sehr einfach und unkompliziert sein


Kennen Sie jemanden - einen Freund, ein Familienmitglied, den Helden des Films, der immer gut gelaunt ist und immer bereit ist, zu helfen, ohne dafür etwas zu verlangen? So sollten gute Tests gestaltet werden. Sie sollten einfach sein, nützlich sein und positive Emotionen hervorrufen. Dies kann durch sorgfältige Auswahl der Testmethoden, Werkzeuge und Ziele erreicht werden. Diejenigen, deren Verwendung den Zeit- und Arbeitsaufwand für die Vorbereitung und Durchführung von Tests rechtfertigt und gleichzeitig gute Ergebnisse liefert. Sie müssen nur testen, was getestet werden muss. Sie sollten sich bemühen, sicherzustellen, dass die Tests einfach und flexibel sind. Manchmal können Sie einige Tests ablehnen, was die Zuverlässigkeit des Projekts aufgrund seiner Einfachheit und Entwicklungsgeschwindigkeit beeinträchtigt.

Tests sollten nicht als normaler Anwendungscode betrachtet werden. Tatsache ist, dass ein typisches Team, das an der Entwicklung eines Projekts beteiligt ist, auf jeden Fall alles in seiner Macht Stehende unternimmt, um es in einem funktionsfähigen Zustand zu halten, dh beispielsweise versucht, ein kommerzielles Produkt so zu betreiben, wie es die Benutzer erwarten. Infolgedessen hat ein solches Team möglicherweise nicht das gute Gefühl, dass es ein weiteres komplexes „Projekt“ unterstützen muss, das durch eine Reihe von Tests dargestellt wird. Wenn die Tests des Hauptcodes zunehmen, immer mehr Aufmerksamkeit auf sich ziehen und zu einem Grund zur ständigen Besorgnis werden, wird die Arbeit an ihnen entweder abgebrochen oder ihnen, wenn sie versuchen, ein angemessenes Niveau beizubehalten, so viel Zeit und Energie geben, dass dies die Arbeit am Hauptprojekt verlangsamt.

Daher sollte der Testcode so einfach wie möglich sein und eine minimale Anzahl von Abhängigkeiten und Abstraktionsebenen aufweisen. Tests sollten so aussehen, dass sie auf einen Blick verstanden werden können. Die meisten Empfehlungen, die wir hier berücksichtigen werden, ergeben sich aus diesem Prinzip.

Abschnitt 1. Anatomie der Tests


▍1. Entwerfen Sie Ihre Tests so, dass der Bericht Ihnen sagt, was in welchem ​​Szenario getestet wird und was von den Tests erwartet wird


Empfehlungen


Der Testbericht sollte angeben, ob die aktuelle Version der Anwendung ihren Anforderungen entspricht. Dies sollte in einer Form erfolgen, die für diejenigen verständlich ist, die mit dem Anwendungscode nicht vertraut sein müssen. Dies kann ein Tester sein, ein DevOps-Spezialist, der das Projekt bereitstellt, oder der Entwickler selbst, der sich das Projekt einige Zeit nach dem Schreiben des Codes angesehen hat. Dies kann erreicht werden, wenn beim Schreiben von Tests die Produktanforderungen im Mittelpunkt stehen. Mit diesem Ansatz kann man sich die Struktur des Tests vorstellen, die aus drei Teilen besteht:

  1. Was genau wird getestet? Zum Beispiel die ProductsService.addNewProduct Methode.
  2. In welchem ​​Szenario und unter welchen Umständen wird der Test durchgeführt? Beispielsweise wird die Reaktion des Systems in einer Situation überprüft, in der der Preis der Waren nicht an die Methode übergeben wurde.
  3. Was sind die erwarteten Testergebnisse? In einer ähnlichen Situation weigert sich das System beispielsweise, das Hinzufügen eines neuen Produkts zu bestätigen.

Folgen der Abweichung von den Empfehlungen


Angenommen, das System konnte nicht bereitgestellt werden, und anhand des Testberichts können Sie nur feststellen, dass es den Test " Add product nicht bestanden hat, bei dem das Hinzufügen eines bestimmten Produkts überprüft wird. Gibt dies Auskunft darüber, was genau schief gelaufen ist?

Richtiger Ansatz


Testinformationen bestehen aus drei Informationen.

 //1.   describe('Products Service', function() { //2.  describe('Add new product', function() {   // 3. ,       it('When no price is specified, then the product status is pending approval', ()=> {     const newProduct = new ProductService().add(...);     expect(newProduct.status).to.equal('pendingApproval');   }); }); }); 

Richtiger Ansatz


Der Testbericht ähnelt einem Dokument mit einer Erklärung der Produktanforderungen.

So sieht es auf verschiedenen Ebenen aus.


Produktanforderungsdokument, Testbenennung, Testergebnisse

  1. Ein Dokument mit Produktanforderungen kann entweder ein spezielles Dokument sein oder in Form einer E-Mail vorliegen.
  2. Wenn Sie Tests benennen, den Testzweck, das Szenario und die erwarteten Ergebnisse beschreiben, müssen Sie die Sprache einhalten, die zur Formulierung der Produktanforderungen verwendet wird. Auf diese Weise können Sie den Testcode und die Produktanforderungen vergleichen.
  3. Die Testergebnisse sollten auch für diejenigen klar sein, die mit dem Anwendungscode nicht vertraut sind oder ihn vollständig vergessen haben. Dies sind Tester, DevOps-Spezialisten und Entwickler, die einige Monate nach dem Schreiben wieder mit dem Code arbeiten.

â–Ť2. Beschreiben Sie, was Sie von den Tests in der Produktsprache erwarten: Verwenden Sie Anweisungen im BDD-Stil


Empfehlungen


Die Entwicklung von Tests in einem deklarativen Stil ermöglicht es denjenigen, die mit ihnen arbeiten, ihre Essenz sofort zu erfassen. Wenn Tests mit einem imperativen Ansatz geschrieben werden, sind sie mit bedingten Konstrukten gefüllt, die ihr Verständnis erheblich erschweren. Nach diesem Prinzip sollten Erwartungen in einer Sprache beschrieben werden, die dem Normalen nahe kommt. Der deklarative BDD-Stil verwendet expect oder should Konstrukte anstelle eines speziellen Codes ihres eigenen Designs. Wenn es in Chai oder Jest keine erforderlichen Anweisungen gibt und sich herausstellt, dass solche Anweisungen häufig benötigt werden, sollten Sie Jest neue „Checks“ hinzufügen oder eigene Plugins für Chai schreiben.

Folgen der Abweichung von den Empfehlungen


Wenn Sie die oben beschriebenen Empfehlungen nicht befolgen, führt dies dazu, dass Mitglieder des Entwicklungsteams weniger Tests schreiben und die lästigen Überprüfungen mit der Methode .skip() überspringen.

Falscher Ansatz


Der Leser dieses Tests muss den ziemlich langen Imperativcode nur vollständig überprüfen, um zu verstehen, was genau im Test getestet wird.

 it("When asking for an admin, ensure only ordered admins in results" , ()={   //,       — "admin1"  "admin2",   "user1"   const allAdmins = getUsers({adminOnly:true});   const admin1Found, adming2Found = false;   allAdmins.forEach(aSingleUser => {       if(aSingleUser === "user1"){           assert.notEqual(aSingleUser, "user1", "A user was found and not admin");       }       if(aSingleUser==="admin1"){           admin1Found = true;       }       if(aSingleUser==="admin2"){           admin2Found = true;       }   });   if(!admin1Found || !admin2Found ){       throw new Error("Not all admins were returned");   } }); 

Richtiger Ansatz


Sie können diesen Test buchstäblich auf einen Blick verstehen.

 it("When asking for an admin, ensure only ordered admins in results" , ()={   //,        const allAdmins = getUsers({adminOnly:true});     expect(allAdmins).to.include.ordered.members(["admin1" , "admin2"]) .but.not.include.ordered.members(["user1"]); }); 

â–Ť3. FĂĽhren Sie Testcode-Flusen mit speziellen Plugins durch


Empfehlungen


Es gibt eine Reihe von Plug-Ins für ESLint, die speziell zum Analysieren von Testcode und zum Auffinden von Problemen in diesem Code entwickelt wurden. Beispielsweise gibt das eslint-plugin-mocha- Plug- in Warnungen aus, wenn der Test auf globaler Ebene geschrieben wurde (und kein Nachkomme von describe() ) oder wenn sich herausstellt, dass die Tests übersprungen wurden , was zu falschen Hoffnungen führen kann, dass alle Tests bestanden werden. Das eslint-plugin-jest-Plugin funktioniert auf ähnliche Weise, z. B. Warnung vor Tests, die keine Anweisungen enthalten, dh vor Tests, die nichts überprüfen.

Folgen der Abweichung von den Empfehlungen


Der Entwickler wird sich freuen zu sehen, dass der Code zu 90% in Tests enthalten ist und 100% der Tests erfolgreich bestanden wurden. Es bleibt jedoch nur in diesem Zustand, bis sich herausstellt, dass viele Tests tatsächlich nichts überprüfen und einige Testskripte einfach übersprungen werden. Man kann nur hoffen, dass niemand Projekte bereitstellt, die auf diese Weise in der Produktion „getestet“ werden.

Falscher Ansatz


Das Testszenario ist voller Fehler, die glücklicherweise mit dem Linter erkannt werden können.

 describe("Too short description", () => { const userToken = userService.getDefaultToken() // *error:no-setup-in-describe, use hooks (sparingly) instead it("Some description", () => {});//* error: valid-test-description. Must include the word "Should" + at least 5 words }); it.skip("Test name", () => {// *error:no-skipped-tests, error:error:no-global-tests. Put tests only under describe or suite expect("somevalue"); // error:no-assert }); it("Test name", () => {*//error:no-identical-title. Assign unique titles to tests }); 

▍4. Halten Sie sich an die Black-Box-Methode - testen Sie nur öffentliche Methoden


Empfehlungen


Das Testen einiger interner Codemechanismen bedeutet eine erhebliche Erhöhung der Belastung der Entwickler und bietet fast keine Vorteile. Wenn eine bestimmte API die richtigen Ergebnisse liefert, lohnt es sich dann, mehrere Stunden damit zu verbringen, ihre internen Mechanismen zu testen und diese Tests, die sehr leicht zu brechen sind, weiterhin auf dem neuesten Stand zu halten? Beim Testen öffentlich verfügbarer Methoden wird auch deren interne Implementierung, obwohl implizit, überprüft. Ein solcher Test führt zu einem Fehler, wenn im System ein Problem auftritt, das zur Ausgabe falscher Daten führt. Dieser Ansatz wird auch als "Verhaltenstest" bezeichnet. Auf der anderen Seite konzentriert sich der Entwickler beim Testen der internen Mechanismen einer bestimmten API (dh unter Verwendung der White-Box-Technik) auf die kleinen Details der Implementierung und nicht auf das Endergebnis des Codes. Tests, die solche Feinheiten überprüfen, können beispielsweise nach einer kleinen Umgestaltung des Codes zu Fehlern führen, obwohl das System weiterhin korrekte Ergebnisse liefert. Infolgedessen erhöht dieser Ansatz die Belastung des Programmierers, die mit der Unterstützung von Testcode verbunden ist, erheblich.

Folgen der Abweichung von den Empfehlungen


Die Tests, die versuchen, die internen Mechanismen eines bestimmten Systems zu erfassen, verhalten sich wie ein Hirtenjunge aus einer Fabel, der Bauern mit den Schreien „Hilfe! Wolf! “Als kein Wolf in der Nähe war. Die Leute rannten zur Hilfe, nur um herauszufinden, dass sie getäuscht worden waren. Und als der Wolf wirklich auftauchte, kam niemand zur Rettung. Solche Tests führen beispielsweise in den Fällen, in denen sich die Namen einiger interner Variablen ändern, zu falsch positiven Ergebnissen. Infolgedessen ist es nicht verwunderlich, dass derjenige, der diese Tests durchführt, bald beginnt, seine "Schreie" zu ignorieren, was letztendlich dazu führt, dass ein wirklich schwerwiegender Fehler unbemerkt bleiben kann.

Falscher Ansatz


Dieser Test testet die internen Mechanismen einer Klasse ohne besonderen Grund fĂĽr solche ĂśberprĂĽfungen.

 class ProductService{ //      //     ,      calculateVAT(priceWithoutVAT){   return {finalPrice: priceWithoutVAT * 1.2};   //           } //  getPrice(productId){   const desiredProduct= DB.getProduct(productId);   finalPrice = this.calculateVATAdd(desiredProduct.price).finalPrice; } } it("White-box test: When the internal methods get 0 vat, it return 0 response", async () => {   //       VAT,      .  ,   ,        expect(new ProductService().calculateVATAdd(0).finalPrice).to.equal(0); }); 

▍5. Wählen Sie die entsprechenden Sicherungsobjekte aus: Vermeiden Sie Mobs und bevorzugen Sie Stubs und Spione


Empfehlungen


Die Verwendung von Testdoppeln beim Testen ist ein notwendiges Übel, da sie mit den internen Mechanismen der Anwendung verbunden sind. Ohne einige von ihnen ist das einfach unmöglich. Hier finden Sie nützliches Material zu diesem Thema. Verschiedene Ansätze zur Verwendung solcher Objekte können jedoch nicht als äquivalent bezeichnet werden. Einige von ihnen - Stummel (Stummel) und Spione (Spion) - zielen darauf ab, die Anforderungen an das Produkt zu testen, müssen jedoch in Form einer unvermeidlichen Nebenwirkung die internen Mechanismen dieses Produkts geringfügig beeinflussen. Mocks hingegen zielen darauf ab, die internen Mechanismen des Projekts zu testen. Daher führt ihre Verwendung zu einer enormen unnötigen Belastung für Programmierer, über die wir oben gesprochen haben, und bietet an, beim Schreiben von Tests die "Black-Box" -Methode einzuhalten.

Stellen Sie sich vor der Verwendung doppelter Objekte eine einfache Frage: „Benutze ich sie, um die beschriebene Funktionalität zu testen, oder könnte sie in den technischen Anforderungen für das Projekt beschrieben werden?“. Wenn die Antwort auf diese Frage negativ ist, kann dies bedeuten, dass Sie das Produkt mit dem White-Box-Ansatz testen, über den wir bereits gesprochen haben.

Wenn Sie beispielsweise herausfinden möchten, ob Ihre Anwendung in einer Situation, in der ein Zahlungsdienst nicht verfügbar ist, ordnungsgemäß funktioniert, können Sie diesen Dienst beenden und die Anwendung etwas empfangen lassen, das darauf hinweist, dass keine Antwort vorliegt. Auf diese Weise können Sie die Reaktion des Systems auf eine ähnliche Situation überprüfen, um festzustellen, ob es sich korrekt verhält. Während eines solchen Tests wird das Verhalten oder die Reaktion oder das Ergebnis der Anwendung unter bestimmten Bedingungen überprüft. In dieser Situation können Sie mit dem Spion überprüfen, ob beim Feststellen eines Rückgangs des Zahlungsdienstes eine bestimmte E-Mail gesendet wurde. Dies ist wiederum eine Überprüfung des Verhaltens des Systems in einer bestimmten Situation, die sicher in den technischen Anforderungen dafür aufgezeichnet ist, beispielsweise in der folgenden Form: "Senden Sie eine E-Mail an den Administrator, wenn die Zahlung nicht erfolgreich ist". Wenn Sie dagegen ein Scheinobjekt verwenden, um einen Zahlungsdienst darzustellen, und die Arbeit beim Zugriff darauf überprüfen, indem Sie übertragen, was von ihm erwartet wird, werden wir über das Testen interner Mechanismen sprechen, die nicht direkt mit der Funktionalität der Anwendung zusammenhängen, und zwar ganz kann sich vielleicht oft ändern.

Folgen der Abweichung von den Empfehlungen


Bei jedem Code-Refactoring mĂĽssen Sie nach allen Moki, Refactoring und deren Code suchen. Infolgedessen wird das Testen des Supports zu einer schweren Belastung, die sie zu Feinden des Entwicklers und nicht seiner Freunde macht.

Falscher Ansatz


Dieses Beispiel zeigt ein Scheinobjekt, das sich auf das Testen der internen Mechanismen der Anwendung konzentriert.

 it("When a valid product is about to be deleted, ensure data access DAL was called once, with the right product and right config", async () => {   //,        const dataAccessMock = sinon.mock(DAL);   // ,           dataAccessMock.expects("deleteProduct").once().withArgs(DBConfig, theProductWeJustAdded, true, false);   new ProductService().deletePrice(theProductWeJustAdded);   mock.verify(); }); 

Richtiger Ansatz


Spione zielen darauf ab, Systeme auf ihre Anforderungen zu testen, beeinflussen jedoch als Nebeneffekt unweigerlich die internen Mechanismen von Systemen.

 it("When a valid product is about to be deleted, ensure an email is sent", async () => {   //,        const spy = sinon.spy(Emailer.prototype, "sendEmail");   new ProductService().deletePrice(theProductWeJustAdded);   //  .       ? ,               (  ) }); 

▍6. Verwenden Sie während des Testens realistische Eingaben, die nicht auf „foo“ beschränkt sind.


Empfehlungen


Oft manifestieren sich Produktionsfehler in einer sehr spezifischen und sogar überraschenden Kombination von Umständen. Dies bedeutet, dass die Wahrscheinlichkeit einer frühzeitigen Erkennung von Fehlern umso höher ist, je realistischer die während des Tests verwendeten Eingabedaten sind. Verwenden Sie diese Option, um Daten zu generieren, die echten, spezialisierten Bibliotheken wie Faker ähneln. Beispielsweise generieren solche Bibliotheken zufällige, aber realistische Telefonnummern, Benutzernamen, Bankkartennummern, Firmennamen und sogar „Lorem Ipsum“ -Texte. Erwägen Sie außerdem, Daten aus Produktionsumgebungen in Tests zu verwenden. Wenn Sie solche Tests auf ein noch höheres Niveau bringen möchten, lesen Sie unsere nächste Empfehlung zu eigenschaftsbasierten Tests.

Folgen der Abweichung von den Empfehlungen


Beim Testen eines Projekts während seiner Entwicklung können alle Tests nur bestanden werden, wenn sie mit unrealistischen Daten wie den Zeilen „foo“ ausgeführt werden. Aber in der Produktion wird das System in einer Situation ausfallen, in der der Hacker ihr so ​​etwas wie @3e2ddsf . ##' 1 fdsfds . fds432 AAAA @3e2ddsf . ##' 1 fdsfds . fds432 AAAA @3e2ddsf . ##' 1 fdsfds . fds432 AAAA .

Falscher Ansatz


Das System besteht diese Tests nur erfolgreich, weil sie unrealistische Daten verwenden.

 const addProduct = (name, price) =>{ const productNameRegexNoSpace = /^\S*$/;//  if(!productNameRegexNoSpace.test(name))   return false;// , -   ,  .     //  -    return true; }; it("Wrong: When adding new product with valid properties, get successful confirmation", async () => {   // "Foo",    ,    ,    false   const addProductResult = addProduct("Foo", 5);   expect(addProductResult).to.be.true;   // :     - ,     //         }); 

Richtiger Ansatz


Es werden randomisierte Daten verwendet, die realen Daten ähnlich sind.

 it("Better: When adding new valid product, get successful confirmation", async () => {   const addProductResult = addProduct(faker.commerce.productName(), faker.random.number());   //   : {'Sleek Cotton Computer',  85481}   expect(addProductResult).to.be.true;   //  ,         ,    .   //     ,    ! }); 

â–Ť 7. Testen Sie Systeme mit mehreren Eingabekombinationen mithilfe von eigenschaftsbasierten Tests


Empfehlungen


In der Regel werden bei Tests kleine Sätze von Eingabedaten verwendet. Selbst wenn sie realen Daten ähneln (darüber haben wir im vorherigen Abschnitt gesprochen), decken solche Tests nur eine sehr begrenzte Anzahl möglicher Kombinationen von Eingaben der untersuchten Entität ab. Zum Beispiel könnte es so aussehen: (method('', true, 1), method("string" , false" , 0)) . Das Problem ist, dass es in der Produktions-API, die mit fünf Parametern aufgerufen wird, abgerufen werden kann die Eingabe von Tausenden verschiedener Varianten ihrer Kombinationen, von denen eine zu einem Fehler führen kann (es wäre angebracht, sich hier an das Fuzzing zu erinnern). Was wäre, wenn Sie einen einzelnen Test schreiben könnten, der automatisch eine bestimmte Methode auf 1000 Kombinationen ihrer Eingaben überprüft und herausfindet, welche Reagiert die Methode falsch? Das Testen auf der Grundlage der Eigenschaftsüberprüfung ist genau das, was uns in einer solchen Situation ist nützlich. Das heißt, im Laufe dieser Kontrollen Test - Modul, es mit allen möglichen Kombinationen von Eingangsdaten aufrufen, die die Wahrscheinlichkeit des Findens ein paar Fehler erhöht. Angenommen , wir haben eine Methode addNewProduct(id, name, isDiscount) und Bibliothek Beim Durchführen von Tests wird es mit vielen Kombinationen von Parametern vom numerischen, Zeichenfolgen- und logischen Typ aufgerufen, z. B. (1, "iPhone", false) , (2, "Galaxy", true) . Es ist möglich, Tests basierend auf der Eigenschaftsüberprüfung unter Verwendung der üblichen Testausführungsumgebung (Mocha, Jest usw.) und unter Verwendung spezieller Bibliotheken wie js-verify oder testcheck durchzuführen (diese Bibliothek verfügt über eine sehr gute Dokumentation).

Folgen der Abweichung von den Empfehlungen


Der Entwickler wählt unbewusst solche Testdaten aus, die nur die Teile des Codes abdecken, die ordnungsgemäß funktionieren. Leider verringert dies die Effektivität des Testens als Mittel zum Erkennen von Fehlern.

Richtiger Ansatz


Testen vieler Eingabemöglichkeiten mithilfe der Mokka-Testcheck-Bibliothek.

 require('mocha-testcheck').install(); const {expect} = require('chai'); const faker = require('faker'); describe('Product service', () => { describe('Adding new', () => {   //  100         check.it('Add new product with random yet valid properties, always successful',     gen.int, gen.string, (id, name) => {       expect(addNewProduct(id, name).status).to.equal('approved');     }); }) }); 

â–Ť8. BemĂĽhen Sie sich, dass der Testcode autark ist, und minimieren Sie externe Hilfsmittel und Abstraktionen


Empfehlungen


Es ist jetzt wahrscheinlich offensichtlich, dass ich mich extrem einfachen Tests verpflichtet fühle. Tatsache ist, dass sich das Entwicklungsteam eines bestimmten Projekts ansonsten tatsächlich mit einem anderen Projekt befassen muss. Um seinen Code zu verstehen, müssen sie wertvolle Zeit verbringen, die sie nicht so viel haben. Über dieses Phänomen ist sehr gut geschrieben: „Ein qualitativ hochwertiger Produktionscode ist ein gut durchdachter Code, und ein qualitativ hochwertiger Testcode ist ein vollständig verständlicher Code. Wenn Sie einen Test schreiben, überlegen Sie, wer die von ihm angezeigte Fehlermeldung sehen wird. Diese Person möchte nicht, um die Fehlerursachen zu verstehen, den Code der gesamten Testsuite oder den Code des Vererbungsbaums der zum Testen verwendeten Dienstprogramme lesen. “

Damit der Leser den Test verstehen kann, ohne seinen Code zu verlassen, sollten Sie bei der Durchführung des Tests die Verwendung von Dienstprogrammen, Hooks oder externen Mechanismen minimieren. Wenn Sie dazu zu oft auf das Kopieren und Einfügen von Code zurückgreifen müssen, können Sie bei einem externen Hilfsmechanismus anhalten, dessen Verwendung die Verständlichkeit des Tests nicht beeinträchtigt. Wenn jedoch die Anzahl solcher Mechanismen zunimmt, verliert der Testcode an Verständlichkeit.

Folgen der Abweichung von den Empfehlungen


, 4 , 2 , ? ! , , .


. ?

 test("When getting orders report, get the existing orders", () => {   const queryObject = QueryHelpers.getQueryObject(config.DBInstanceURL);   const reportConfiguration = ReportHelpers.getReportConfig();//   ?        userHelpers.prepareQueryPermissions(reportConfiguration);//  ?         const result = queryObject.query(reportConfiguration);   assertThatReportIsValid();//  ,           -    expect(result).to.be.an('array').that.does.include({id:1, productd:2, orderStatus:"approved"});   //      ?        }) 

Richtiger Ansatz


, .

 it("When getting orders report, get the existing orders", () => {   // ,           const orderWeJustAdded = ordersTestHelpers.addRandomNewOrder();   const queryObject = newQueryObject(config.DBInstanceURL, queryOptions.deep, useCache:false);   const result = queryObject.query(config.adminUserToken, reports.orders, pageSize:200);   expect(result).to.be.an('array').that.does.include(orderWeJustAdded); }) 

â–Ť9. :


Empfehlungen


, , , , . . , ( ) . — , ( , ). — , , , , . , , . — , , , , ( , , , ).

Folgen der Abweichung von den Empfehlungen


, . . . . , , , .


. , .

 before(() => { //       .   ? - ,  -   json-. await DB.AddSeedDataFromJson('seed.json'); }); it("When updating site name, get successful confirmation", async () => { // ,  ,  "Portal", ,           const siteToUpdate = await SiteService.getSiteByName("Portal"); const updateNameResult = await SiteService.changeName(siteToUpdate, "newName"); expect(updateNameResult).to.be(true); }); it("When querying by site name, get the right site", async () => { // ,  ,  "Portal", ,           const siteToCheck = await SiteService.getSiteByName("Portal"); expect(siteToCheck.name).to.be.equal("Portal"); //!      :[ }); 

Richtiger Ansatz


, , .

 it("When updating site name, get successful confirmation", async () => { //           const siteUnderTest = await SiteService.addSite({   name: "siteForUpdateTest" }); const updateNameResult = await SiteService.changeName(siteUnderTest, "newName"); expect(updateNameResult).to.be(true); }); 

â–Ť10. , . expect


Empfehlungen


, , try-catch-finally catch . , , , .

Chai, expect(method).to.throw . Jest: expect(method).toThrow() . , . , , .

Folgen der Abweichung von den Empfehlungen


, , , .


, try-catch .

 it("When no product name, it throws error 400", async() => { let errorWeExceptFor = null; try { const result = await addNewProduct({name:'nest'});} catch (error) { expect(error.code).to.equal('InvalidInput'); errorWeExceptFor = error; } expect(errorWeExceptFor).not.to.be.null; //    ,         //  ,     null,       }); 

Richtiger Ansatz


expect , , .

 it.only("When no product name, it throws error 400", async() => { expect(addNewProduct)).to.eventually.throw(AppError).with.property('code', "InvalidInput"); }); 

â–Ť11. ,


Empfehlungen


. , (smoke test), -, , . - . , , , #cold , #api , #sanity . . , Mocha -g ( --grep ).

Folgen der Abweichung von den Empfehlungen


, , , , , , . .

Richtiger Ansatz


#cold-test , . , -, , — .

 //    ( ,    ),     // ,        //   describe('Order service', function() { describe('Add new order #cold-test #sanity', function() {   it('Scenario - no currency was supplied. Expectation - Use the default currency #sanity', function() {     //-    }); }); }); 

â–Ť12.


Empfehlungen


, Node.js-. , , Node.js .

TDD — , , . , . , , Red-Green-Refactor . , - , , , , , . , . ( — , , ).

Folgen der Abweichung von den Empfehlungen


— , . .

2.


â–Ť13. ,


Empfehlungen


, , 10 , . , . , . , (, ), , , , ? - ?

, . , 2019 , , TDD, — , . , , , . , IoT-, , , - Kafka RabbitMQ, . - , , , . , , , , ? (, , Alexa) , , .

, ( ). , , , , , , . , , - API — Consumer-Driven Contracts . , , , , . , , , , , . , , .

, TDD . , TDD , . , , , .

Folgen der Abweichung von den Empfehlungen


— ( ), .

Richtiger Ansatz


. . , , Node.js, .

â–Ť14. ,


Empfehlungen


. — . , , . , , - , , - ? , . , : TDD, — .

«». API, - , (, , , , , ). , , , (, ). , , , , , , .

Folgen der Abweichung von den Empfehlungen


, , , , 20.

Richtiger Ansatz


supertest , API, Express, .


API, Express

â–Ť15. , API, Consumer-Driven Contracts


Empfehlungen


, , , , . , , - , , , - . «-22» : . , , . , Consumer-Driven Contracts PACT .

. . PACT , ( «»). , , PACT, , , . , , , , .

Folgen der Abweichung von den Empfehlungen


.

Richtiger Ansatz



Consumer-Driven Contracts

, , B , . B .

â–Ť16.


Empfehlungen


(middleware) - , , - , Express-. . , , . , , JS- {req,res} . , «» (, Sinon ) , {req,res} . , , , . node-mock-http , , , . , , HTTP-, -.

Folgen der Abweichung von den Empfehlungen


Express .

Richtiger Ansatz


Express-.

 // ,     const unitUnderTest = require('./middleware') const httpMocks = require('node-mocks-http'); //  Jest,     Mocha    describe()  it() test('A request without authentication header, should return http status 403', () => { const request = httpMocks.createRequest({   method: 'GET',   url: '/user/42',   headers: {     authentication: ''   } }); const response = httpMocks.createResponse(); unitUnderTest(request, response); expect(response.statusCode).toBe(403); }); 

â–Ť17.


Empfehlungen


, , , , , , . , , - . , , , ( , , ), , ( — ) . , : SonarQube ( 2600 GitHub) Code Climate ( 1500 ).

Folgen der Abweichung von den Empfehlungen


, , . . , .

Richtiger Ansatz


Code Climate.


Code Climate

â–Ť18. , Node.js


Empfehlungen


, , . , , , - , . , - , , , , ? , , ? , API ?

Netflix - . , , , , . , - — Chaos Monkey . , , , . Kubernetes — kube-monkey . , Node.js? , , , V8 1.7 . . node-chaos , -.

Folgen der Abweichung von den Empfehlungen


, , , .

Richtiger Ansatz


npm- chaos-monkey , Node.js.


chaos-monkey

Zusammenfassung


, Node.js-. , . .

Liebe Leser! - ?

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


All Articles