Door ervoor te zorgen dat uw toepassing wordt getest, kunt u het aantal fouten in uw code verminderen, de onderhoudbaarheid van uw toepassing verbeteren en goed gestructureerde code ontwerpen.
Testen aan clientzijde-eenheden biedt verschillende uitdagingen dan testen aan serverzijde. Wanneer het gaat om client-side code, zult u merken dat u moeite heeft om applicatielogica te scheiden van de DOM-logica en om JavaScript-code in het algemeen te structureren. Gelukkig zijn er veel grote clientside-testbibliotheken om je code te testen, statistieken over de testrapporten te maken en de complexiteit ervan te analyseren.
Ten eerste is unit testing in het algemeen een manier om bugs te verminderen door ervoor te zorgen dat uw applicatie functioneert zoals het hoort. Buiten dat zijn echter de noties van Test Driven Development (TDD) en Behavior Driven Development (BDD).
Deze twee teststrategieën voor eenheden helpen u bij het ontwerpen van uw toepassing door tests te schrijven voor je schrijft je applicatielogica. Door de tests te schrijven voordat u de code schrijft, geeft u uzelf de gelegenheid om na te denken over het ontwerp van uw toepassing.
Dit gebeurt omdat wanneer u tests schrijft, u in feite probeert de API te ontwerpen voor de manier waarop u met uw code omgaat, zodat u daardoor beter inzicht krijgt in het ontwerp. Eerst testen zal je snel alle onvolkomenheden laten zien die je in je ontwerp hebt, omdat je testcode schrijft die in essentie de code gebruikt die je schrijft!
TDD is een codevindingproces
Je zult leren dat TDD je helpt je code te ontdekken terwijl je het schrijft. TDD wordt zeer snel samengevat als "Rood, Groen, Refactor". Wat dit betekent is dat je een test schrijft, genoeg code schrijft om de test te maken mislukken eerste. Dan, u schrijft de code waarmee uw test slaagt. Daarna bedenk je wat je net hebt geschreven en refacteer je het. Leuk en gemakkelijk.
BDD is een iets andere kijk op TDD en is meer gebaseerd op zakelijke vereisten en specificaties.
Er zijn vele redenen waarom u uw code aan de kant van de klant zou moeten testen. Zoals eerder vermeld, zal het helpen om bugs te verminderen en u helpen bij het ontwerpen van uw toepassing. Tests aan de kant van de cliënt zijn ook belangrijk omdat het u de kans biedt om uw front-endcode te testen, los van uw presentatie. Met andere woorden, een van de voordelen is dat u uw JavaScript-code kunt testen zonder dat u een applicatieserver draait. U voert eenvoudig de tests uit en zorgt ervoor dat dingen werken zonder rond te klikken en dingen te testen. In veel gevallen hoeft u zelfs geen toegang tot internet te hebben, zolang uw tests correct zijn ingesteld.
Omdat JavaScript zo'n belangrijke rol speelt in moderne webontwikkeling, is het belangrijk om te leren hoe je code kunt testen en de kans verkleint dat bugs hun weg vinden naar productiecode. Je baas vindt het niet leuk als dat gebeurt en jij ook niet! Een goede plek om aan de slag te gaan met testen aan clientzijde is eigenlijk het schrijven van tests rond een foutenrapport. Dit stelt je in staat oefenexamens te oefenen wanneer je geen plek hebt om helemaal opnieuw te beginnen.
Een andere reden om uw code aan de kant van de klant te testen, is dat wanneer er eenmaal een reeks tests bestaat en deze een fatsoenlijke dekking heeft over uw code, wanneer u zich gereed maakt om nieuwe functies aan uw code toe te voegen, kunt u de nieuwe functie toevoegen - Voer uw tests uit en zorg ervoor dat u niet achteruitging en geen bestaande functies breekt.
Aan de slag met testen aan de kant van de klant kan ontmoedigend zijn als je het nog nooit eerder hebt gedaan. Een van de moeilijkste aspecten van testen aan clientzijde is het uitzoeken van de beste manier om de DOM te isoleren van de logica van uw toepassing. Dat betekent vaak dat je een soort abstractie nodig hebt over de DOM. De eenvoudigste manier om dit te bereiken, is via een client-side-framework zoals Knockout.js, Backbone.js of Angular.js, om er maar een paar te noemen.
Wanneer u een dergelijke bibliotheek gebruikt, kunt u minder nadenken over hoe uw pagina in de browser wordt weergegeven en meer over de functies van uw toepassing. Het is echter niet zo dat het onmogelijk is om een eenheid te testen met alleen maar JavaScript. In dat geval zal uw leven veel eenvoudiger zijn als u de code zodanig ontwerpt dat de DOM gemakkelijk kan worden geabstraheerd.
Er zijn veel verschillende testbibliotheken om uit te kiezen, hoewel de drie koplopers meestal QUnit zijn, Mocha en Jasmine.
Jasmine en Mocha zijn beiden afkomstig van de BDD-school voor het testen van eenheden, terwijl KWnit slechts een eigen unit testing-framework is.
Voor de rest van dit bericht zullen we onderzoeken of het gebruik van QUnit als drempel voor toegang tot tests aan de kant van de cliënt erg laag is. Bekijk deze gedetailleerde intro voor meer informatie over QUNIT.
Aan de slag met QUnit is extreem eenvoudig. De volgende HTML is alles wat je nodig hebt:
QUnit Voorbeeld
Laten we voor de volgende voorbeelden aannemen dat we een kleine widget bouwen waarin u een postcode invoert in een tekstvak en de bijbehorende waarden voor de stad, provincie en provincie retourneert met behulp van Geonames. In eerste instantie wordt alleen een postcode weergegeven, maar zodra de postcode vijf tekens bevat, worden de gegevens opgehaald uit Geonames. Als er gegevens kunnen worden gevonden, worden er enkele velden weergegeven met de resulterende informatie over de stad, provincie en provincie. We zullen ook Knockout.js gebruiken. De eerste stap is het schrijven van een mislukte test.
Als je het ontwerp kort voor de eerste test doorloopt, moeten er waarschijnlijk ten minste twee viewModels zijn, dus dat is een goed uitgangspunt. Om te beginnen, zullen we een QUNIT-module en onze eerste test definiëren:
module ("zip-code retriever"); test ("viewmodellen zouden moeten bestaan", functie () ok (FormViewModel, "Een viewModel voor ons formulier zou moeten bestaan"); ok (AddressViewModel, "Een viewModel voor ons adres zou moeten bestaan"););
Als u deze test uitvoert, mislukt deze, nu kunt u de code gaan schrijven om deze te laten slagen:
var AddressViewModel = function (options) ; var FormViewModel = function () this.address = new AddressViewModel (); ;
Je ziet deze keer groen in plaats van rood. Tests als deze lijken in eerste instantie een beetje raar, maar ze zijn nuttig omdat ze je dwingen om op zijn minst in een vroeg stadium van je ontwerp te denken.
De volgende test die we zullen schrijven zal werken op de AddressViewModel
functionaliteit. We weten uit de specificatie van deze widget dat de andere velden eerst moeten worden verborgen totdat de gegevens voor de postcode zijn gevonden.
module ("adresaanzichtmodel"); test ("moet stadstatusgegevens tonen als een postcode is gevonden", function () var address = new AddressViewModel (); ok (! address.isLocated ()); address.zip (12345); address.city (" foo "); address.state (" bar "); address.county (" bam "); ok (address.isLocated ()););
Geen van de code hiervoor is al geschreven, maar het idee hier is dat het islocated
zal een berekende waarneembare zijn, die terugkeert waar
alleen als de zip, stad, staat en provincie allemaal waar zijn. Deze test zal dus in eerste instantie mislukken, laten we nu de code schrijven om deze te laten slagen.
var AddressViewModel = function (options) options = options || ; this.zip = ko.observable (options.zip); this.city = ko.observable (options.city); this.state = ko.observable (options.state); this.county = ko.observable (options.county); this.isLocated = ko.computed (function () retourneer this.city () && this.state () && this.county () && this.zip ();, this); this.initialize (); ;
Als u de tests opnieuw uitvoert, ziet u groen!
Dit is op zijn eenvoudigst, hoe je TDD kunt gebruiken om frontend tests te schrijven. In het ideale geval schrijft u na elke mislukte test de eenvoudigste code waarmee de test wordt doorgegeven en gaat u vervolgens terug en past u de code aan. Je kunt echter veel meer leren over TDD-praktijken, dus ik raad aan het verder te lezen en verder te bestuderen, maar de voorgaande voorbeelden zijn voldoende om je hoofd eerst aan het denken te zetten over het schrijven van tests.
Sinon.js is een JavaScript-bibliotheek die JavaScript-objecten kan bespioneren, stomp maken en moppen. Bij het schrijven van eenheidscontroletests wilt u ervoor zorgen dat u alleen een bepaalde "eenheid" van code kunt testen. Dit betekent vaak dat je een soort van spot of strubing van afhankelijkheden moet doen om de code die wordt getest te isoleren.
Sinon heeft hiervoor een uiterst eenvoudige API. De Geonames API ondersteunt het ophalen van gegevens via een JSONP-eindpunt, wat betekent dat we het eenvoudig kunnen gebruiken $ .ajax
.
In het ideale geval hoef je echter niet afhankelijk te zijn van de Geonames-API in je tests. Ze kunnen tijdelijk niet werken, je internet kan doodgaan en het is ook gewoon langzamer om de ajax-oproep te maken. Sinon tot de redding.
test ("zou alleen moeten proberen om gegevens te krijgen als er 5 tekens zijn", function () var address = new AddressViewModel (); sinon.stub (jQuery, "ajax"). returns (done: $ .noop); address .zip (1234); ok (! jQuery.ajax.calledOnce); address.zip (12345); ok (jQuery.ajax.calledOnce); jQuery.ajax.restore (););
Hier in deze test doen we een paar dingen. Allereerst het sinon.stub
functie gaat eigenlijk over proxy jQuery.ajax
en voeg de mogelijkheid toe om te zien hoe vaak het is aangeroepen en vele andere beweringen. Zoals de test luidt, "zou alleen moeten proberen om gegevens te krijgen als er 5 tekens zijn", gaan we ervan uit dat wanneer het adres is ingesteld op slechts"1234
", dat er nog geen ajax-oproep is gedaan, stel het dan in op"12345
en op dat moment moet een ajax-oproep worden gedaan.
We moeten dan herstellen jQuery.ajax
in zijn oorspronkelijke staat, omdat we goede burgers zijn van het testen van eenheden en onze testen atomair willen houden. Het is belangrijk om uw tests atomisch te houden om ervoor te zorgen dat de ene test niet afhankelijk is van een andere test en dat er geen gedeelde status is tussen de tests. Ze kunnen dan ook in willekeurige volgorde worden uitgevoerd.
Nu de test is geschreven, kunnen we deze uitvoeren, bekijken dat deze mislukt en vervolgens de code schrijven die het ajax-verzoek naar Geonames uitvoert.
AddressViewModel.prototype.initialize = function () this.zip.subscribe (this.zipChanged, this); ; AddressViewModel.prototype.zipChanged = function (value) if (value.toString (). Length === 5) this.fetch (value); ; AddressViewModel.prototype.fetch = function (zip) var baseUrl = "http://www.geonames.org/postalCodeLookupJSON" $ .ajax (url: baseUrl, data: "postalcode": zip, "country": " us ", type:" GET ", dataType:" JSONP "). done (this.fetched.bind (this)); ;
Hier abonneren wij ons op wijzigingen van de postcode. Wanneer het verandert, de zipChanged
methode wordt aangeroepen. De zipChanged
methode zal controleren om te zien of de lengte van de waarde van de zip is 5
. Wanneer het bereikt 5
, de halen
methode wordt aangeroepen. Hier komt de Sinon-splitsing binnen om te spelen. Op dit punt, $ .ajax
is eigenlijk een Sinon-streepje. Zo calledOnce
zal dan zijn waar
in de test.
De laatste test die we zullen schrijven is voor wanneer de gegevens terugkomen van de Geonames-service:
test ("moet stad info instellen op basis van zoekresultaat", functie () var address = new AddressViewModel (); address.fetched (postalcodes: [adminCode1: "foo", adminName2: "bar", placeName: "bam "]); equal (address.city ()," bam "); equal (address.state ()," foo "); equal (address.county ()," bar "););
Deze test test hoe de gegevens van de server worden ingesteld op de AddressViewmodel
. Voer het uit, zie wat rood. Maak het nu groen:
AddressViewModel.prototype.fetched = function (data) var cityInfo; if (data.postalcodes && data.postalcodes.length === 1) cityInfo = data.postalcodes [0]; this.city (cityInfo.placeName); this.state (cityInfo.adminCode1); this.county (cityInfo.adminName2); ;
De opgehaalde methode zorgt er gewoon voor dat er een array van is postalcodes
in de gegevens van de server en stelt vervolgens de overeenkomstige eigenschappen in op de ViewModel
.
Zie je hoe gemakkelijk dit nu is? Zodra je de stroom krijgt om dit te doen, zul je bijna nooit willen niet TDD opnieuw. Je krijgt uiteindelijk leuke kleine functies die kunnen worden getest. Je dwingt jezelf om na te denken over hoe je code interageert met zijn afhankelijkheden. En nu hebt u een reeks tests die moet worden uitgevoerd wanneer een andere nieuwe vereiste aan de code wordt toegevoegd. Zelfs als je iets mist en er is een fout in de code, kun je nu gewoon een nieuwe test toevoegen aan de suite, om te bewijzen dat je de bug hebt opgelost! Het wordt eigenlijk een beetje verslavend.
Testverslag biedt een eenvoudige manier om te evalueren hoeveel van uw code is getest door een unit-test. Het is vaak moeilijk en niet de moeite waard om 100% dekking te bereiken, maar doe er alles aan om het zo hoog mogelijk te krijgen.
Een van de nieuwere en eenvoudigere dekkingsbibliotheken is Blanket.js. Het gebruik met QUnit is doodeenvoudig. Pak de code eenvoudigweg van hun startpagina of installeer deze met Bower. Voeg vervolgens deken toe als een bibliotheek onder aan uw qunit.html
bestand en voeg vervolgens toe data-afdekking
naar alle bestanden waarop u dekkingstests wilt uitvoeren.
Gedaan. Supereenvoudig, en nu krijg je een optie in je QUnit-hardloper voor het tonen van de dekking:
In dit voorbeeld kunt u zien dat de testdekking niet helemaal 100% is, maar in dit geval, omdat er niet veel code is, is het gemakkelijk om het tegen te houden. U kunt daadwerkelijk een drill-down maken en de exacte functies bekijken die nog niet zijn behandeld:
Hier in dit geval, de FormViewModel
is nooit geïnstantieerd in de tests en daarom ontbreekt de testdekking. U kunt dan gewoon een nieuwe test toevoegen die een exemplaar van de FormViewModel
, en misschien een bewering schrijven die controleert dat het adres
eigendom is aanwezig en is een instanceOf
de AddressViewModel
.
U krijgt dan het plezier 100% testbereik te zien.
Naarmate uw applicaties groter en groter worden, is het fijn om een statische analyse van uw JavaScript-code uit te voeren. Een geweldig hulpmiddel voor het uitvoeren van analyses op JavaScript wordt Plato genoemd.
Je kan lopen Plato
door het te installeren via NPM
met:
npm install -g plato
Dan kun je rennen Plato
in een directory van JavaScript-code:
plato -r -d js / app-rapporten
Hiermee wordt Plato uitgevoerd op alle JavaScript in "js / app
"en geef de resultaten weer in rapporten
. Plato voert allerlei statistieken uit op uw code, inclusief gemiddelde regels code, een berekende onderhoudbaarheidsscore, JSHint, moeilijke, geschatte fouten en meer.
Er is niet veel te zien in die vorige afbeelding, simpelweg omdat voor de code waaraan we hebben gewerkt, er maar één bestand is, maar wanneer je begint te werken met een grote applicatie die veel bestanden en coderegels bevat , je zult de informatie vinden die het je enorm nuttig maakt.
Het houdt zelfs bij wanneer u het hebt uitgevoerd, zodat u kunt zien hoe uw statistieken in de loop van de tijd veranderen.
Hoewel het testen van de cliëntzijde een moeilijke propositie lijkt, zijn er zoveel geweldige tools om deze dagen te gebruiken om het super gemakkelijk te maken. Dit artikel krast nauwelijks nog het oppervlak van alle dingen die er tegenwoordig zijn om tests aan clientzijde eenvoudig te maken. Het kan een vervelende klus zijn, maar je zult merken dat de voordelen van het hebben van een testsuite en toetsbare code op den duur zwaarder wegen dan dat. Hopelijk kun je met de stappen die hier worden beschreven snel beginnen met het testen van de code aan de kant van de klant.