De beginnershandleiding voor unit-testen een testbare plug-in bouwen

In het eerste deel van deze serie hebben we op hoog niveau gekeken naar testmethodieken en hebben we enkele gevallen gegeven waarom het voor ons nuttig is om te beginnen met onze WordPress-projecten. We hebben ook de tijd genomen om PHPUnit en de WordPress-tests in te stellen om te beginnen met het bouwen van onze eerste testbare plug-in.

In dit laatste artikel gaan we een methodologie voor het testen van eenheden definiëren, beginnen deze in ons werk op te nemen en weglopen met een volledig functionele (hoewel eenvoudige) plug-in die ook een kleine set tests heeft om ervoor te zorgen dat deze precies werkt zoals verwacht.


Een eenheidstestmethodologie

Als het gaat om testen, zijn er over het algemeen twee manieren om dit te doen:

  • Schrijf uw tests en schrijf vervolgens code om uw tests te laten slagen
  • Schrijf uw code en schrijf tests die slagen

In mijn ervaring is de eerste aanpak altijd beter. Toegegeven, dit is praktisch onmogelijk om te doen binnen de context van een applicatie die al bestaat, maar als je van de grond af begint - wat we zijn - is het een betere aanpak en daarom: als je eenmaal een applicatie hebt geschreven, weet hoe het werkt. Als zodanig kan het buitengewoon moeilijk zijn om tests te schrijven die de toepassing rekken wanneer u inherent weet hoe het moet functioneren.

Daarom vind ik het beter om de tests te schrijven eerste. Op deze manier omvatten uw tests niet alleen de manier waarop het programma is vermeend om te werken, maar het wordt ook een vorm van documentatie die laat zien welke functionaliteit is bedoeld en uiteindelijk een fout oplevert als de functionaliteit niet presteert zoals zou moeten.

Met dat in het achterhoofd, gaan we bouwen met deze eenvoudige methode:

  • Schrijf een test en voer deze uit. Het zal duidelijk mislukken.
  • Schrijf code die probeert de test te laten slagen.
  • Als de test slaagt, gaan we verder met de volgende functie; anders herhalen we het proces totdat het slaagt.

Ten slotte zal onze plug-in als een opfriscursus een speciaal welkomstbericht aan de bezoeker geven op basis van of ze via Google of Twitter hebben doorgeklikt naar de site. We zullen dit ook op zo'n manier schrijven dat het gemakkelijker zal zijn om uit te breiden met aanvullende diensten, mocht je dat in de toekomst willen doen.


Een testbare plug-in bouwen

Op dit moment is het tijd om wat code te schrijven; In tegenstelling tot de meeste projecten zullen we echter nog niet in WordPress-specifieke code springen. In plaats daarvan gaan we onze eenheidstestklasse wegstrepen. Als je de map van je plug-in hebt gestructureerd op basis van wat we in het eerste bericht hebben gedeeld of hoe we het op GitHub hebben geconfigureerd, zou je een hello_reader_tests.php bestand in uw proeven / wordpress-testen directory. Je hoeft die organisatie natuurlijk niet te volgen, maar het zal helpen als we door het project gaan.

Laten we de eenheidstestklasse afstrepen:

require_once ('... / ... / plugin.php'); klasse Hello_Reader_Tests breidt WP_UnitTestCase  // eindklasse uit

Probeer nu de test uit te voeren met behulp van de terminal met behulp van een PHP-eenheid. Ervan uitgaande dat u PHP-eenheid uitvoert vanuit uw lokale MAMP-installatie, zou u moeten kunnen invoeren:

$ /Applications/MAMP/bin/php/php5.3.6/bin/phpunit ./hello_reader_tests.php

Op dit moment zou u een fout moeten zien:

Dat is goed! Het betekent dat PHPUnit is geïnstalleerd en actief is en dat uw WordPress Testing-framework klaar is om te gebruiken. De test is mislukt omdat we eigenlijk geen tests hebben geschreven. Laten we beginnen om dat te doen.

Onze eerste test

Laten we eerst een test schrijven om ervoor te zorgen dat onze plug-in wordt geïnitialiseerd, geïnstantieerd en klaar is om getest te worden. Herinner eerder in het eerste artikel dat we een verwijzing naar het exemplaar van Hello Reader in de PHP hebben opgeslagen $ GLOBALS matrix. Op deze manier hebben we toegang tot dat exemplaar via het testraamwerk. Dus laten we onze unit test bijwerken om er zo uit te zien:

Houd er rekening mee dat ik omwille van de ruimte code-opmerkingen weglaat, maar de plug-in en tests met volledige commentaar zijn beschikbaar op GitHub.

require_once ('... / ... / plugin.php'); klasse Hello_Reader_Tests breidt WP_UnitTestCase uit private $ plugin; functie setUp () parent :: setUp (); $ this-> plugin = $ GLOBALS ['hello-reader'];  // end setup function testPluginInitialization () $ this-> assertFalse (null == $ this-> plugin);  // end testPluginInitialization // end class

Hierboven hebben we een verwijzing naar het exemplaar van de plug-in ingesteld, zodat we er toegang toe hebben tijdens onze unit-tests. We gebruiken de opstelling methode om de referentie naar de plug-in te pakken $ GLOBALS. Merk echter op dat we een andere functie hebben geïntroduceerd genaamd testPluginInitialization. Deze functie verifieert dat de referentie die we hebben ingesteld in de opstelling methode is niet nul.

Als u de tests opnieuw uitvoert, moet u nu een slaagtest maken en moet uw terminal er als volgt uitzien:

Er is hier een belangrijke afhaalmaaltijd: Merk op dat de enkele functie die we hierboven hebben verstrekt een duidelijk doel heeft: om te controleren of de plug-in correct is geïnitialiseerd. De functienaam is duidelijk en bevat een enkele assert-instructie. Dit is een geweldige manier om onze resterende tests in de eerste plaats te modelleren, omdat het het gemakkelijk maakt om fouten te vinden wanneer ze verschijnen. Denk er zo over na: als u een aantal verschillende assert-statements in één functie opneemt, zal het moeilijk zijn om te bepalen welke assert-statement faalt.

De eerste functie

Nu we kennis hebben gemaakt met het schrijven van eenheidstests, unittests uitvoeren en evalueren hoe ze slagen of hoe ze falen, laten we beginnen met het implementeren van functionaliteit voor de plug-in. Allereerst moeten we een filter instellen voor de inhoud, omdat we tekst aan het begin van de inhoud gaan toevoegen. In navolging van de methodologie die we eerder in dit artikel hebben gedefinieerd, laten we eerst onze test schrijven.

Deze specifieke test zal kijken of we een specifieke set tekst aan het eerste deel van de post hebben toegevoegd:

function testAddWelcomeMessage () $ this-> assertEquals ('TEST CONTENT', $ this-> plugin-> add_welcome_message ('Dit is bijvoorbeeld postinhoud.Dit simuleert dat WordPress zou terugkeren bij het bekijken van een blogpost.'), 'add_welcome_message ( ) voegt een welkomstbericht toe aan de berichtinhoud. ');  // end testAddWelcomeMessage

Als u de test precies uitvoert zoals deze is, mislukt deze niet eens - in plaats daarvan retourneert PHPUnit een fatale fout omdat de methode niet is gedefinieerd in de plug-in. Dus laten we dat nu toevoegen. Update de plug-in om er als volgt uit te zien:

class Hello_Reader function __construct () add_filter ('the_content', array (& $ this, 'add_welcome_message'));  // einde constructor publieke functie add_welcome_message ($ content)  // end add_welcome_message // einde klasse

Probeer nu de test uit te voeren. De test zal niet bombarderen, maar je zou eigenlijk een fout moeten zien samen met een duidelijke boodschap waarom de test faalde:

1) Hello_Reader_Tests :: testAddWelcomeMessage add_welcome_message () voegt een welkomstbericht toe aan de berichtinhoud. Kan niet beweren dat nul-overeenkomsten overeenkomen met 'TEST CONTENT'

Dus, in overeenstemming met onze methodologie, willen we deze test laten slagen. Om dit te doen, moeten we ervoor zorgen dat de inhoud van de post de reeks tekst bevat - in dit geval, 'TEST CONTENT', om het te laten passeren. Dus laten we dit proberen. Werk de overeenkomstige functie in de plug-in bij om de tekenreeks vóór de inhoud toe te voegen:

openbare functie add_welcome_message ($ content) retourneer 'TEST CONTENT'. $ Inhoud;  // end add_welcome_message

En nogmaals, we herhalen de test alleen om te zien dat hij faalt. Als u onze test opmerkt, is dit omdat het op zoek is naar onze inhoud is gelijk aan de 'TEST CONTENT' draad. In plaats daarvan moeten we ervoor zorgen dat de tekenreeks begint met de inhoud. Dit betekent dat we onze test moeten updaten. Gelukkig heeft PHPUnit een assertContains-functie. Dus laten we onze code updaten om hem te gebruiken:

function testAddWelcomeMessage () $ this-> assertContains ('TEST CONTENT', $ this-> plugin-> add_welcome_message ('Dit is een voorbeeld van een post-inhoud.) Dit simuleert dat WordPress zou terugkeren bij het bekijken van een blogpost.'), 'add_welcome_message ( ) voegt een welkomstbericht toe aan de berichtinhoud. ');  // end testAddWelcomeMessage

Voer opnieuw de test opnieuw uit en u zou moeten zien dat de test nu slaagt. Geweldig! Nu moeten we aangepaste berichten schrijven voor mensen afkomstig van Twitter en mensen afkomstig van Google.

Onze Twitter-bezoekers verwelkomen

Er zijn een aantal verschillende manieren waarop we kunnen controleren hoe een gebruiker op een bepaalde pagina is terechtgekomen. Soms kunnen we de waarden in de $ _GET array, soms kunnen we de $ _SERVER array, of soms kunnen we de sessie van een gebruiker checken. Voor de doeleinden van dit voorbeeld gaan we op zoek naar 'twitter.com' in de $ _SERVER [ 'HTTP_REQUEST']. Ik zeg dit gewoon zodat jullie kunnen volgen wat we in de code doen.

Dus, in het algemeen gesproken, de add_welcome_message moet controleren of het verzoek afkomstig is van Twitter en het bericht vervolgens op de juiste manier aanpassen. Omdat we elk onderdeel van functionaliteit testen, kunnen we een functie schrijven die kan evalueren of het verzoek afkomstig is van Twitter. Dus laten we een nieuwe test schrijven:

In de plug-in:

openbare functie is_from_twitter ()  // end is_from_twitter

In de test:

function testIsComingFromTwitter () $ _SERVER ['HTTP_REFERER'] = 'http://twitter.com'; $ this-> assertTrue ($ this-> plugin-> is_from_twitter (), 'is_from_twitter () zal true retourneren wanneer de verwijzende site Twitter is.');  // einde testIsComingFromTwitter

We zijn duidelijk de spoofing van de HTTP_REFERER waarde, maar dat is prima voor de doeleinden van dit voorbeeld. Het punt is nog steeds: voer de test uit, het zal mislukken en daarom zullen we de functie in de plug-in moeten implementeren om het te laten slagen:

public function is_from_twitter () return strpos ($ _SERVER ['HTTP_REFERER'], 'twitter.com')> 0;  // end is_from_twitter

Het opnieuw uitvoeren van de test moet nu resulteren in een slaagtest. Maar wacht even - we moeten compleet zijn. Laten we ervoor zorgen dat we een test uitvoeren om te controleren of deze functie niet werkt wanneer de verwijzer is niet van Twitter.

function testIsNotComingFromTwitter () // Spoofing de HTTP_REFERER voor doeleinden van deze test en de bijbehorende blogpost $ _SERVER ['HTTP_REFERER'] = 'http://facebook.com'; $ this-> assertFalse ($ this-> plugin-> is_from_twitter (), 'is_from_twitter () zal true retourneren wanneer de verwijzende site Twitter is.');  // einde testIsNotComingFromTwitter

Merk op dat we de hebben bijgewerkt HTTP_REFERER en we zijn veranderd assertTrue naar assertFalse. Het toestaan ​​van al het andere is correct, voer de tests uit en ze moeten slagen.

Herhaal hetzelfde voor Google

Als u een aangepast bericht voor Google opgeeft, heeft u hetzelfde nodig dat we voor Twitter hebben gedaan, dat wil zeggen: spoof het HTTP_REFERER en retourneer dan waar of niet waar voor de helperfunctie. Dus, om overbodig klinken te voorkomen, zal ik dit gedeelte zo beknopt mogelijk houden. Dezelfde stappen moeten worden gevolgd als voor Twitter.

Eerst stopen we de hulpfunctie in de plug-in:

openbare functie is_from_google ()  // end is_from_google

Vervolgens testen we de test:

function testIsComingFromGoogle () $ _SERVER ['HTTP_REFERER'] = 'http://google.com'; $ this-> assertTrue ($ this-> plugin-> is_from_google (), 'is_from_google () zal true retourneren wanneer de verwijzende site Google is.');  // end testIsComingFromGoogle

Het uitvoeren van de test zoals deze nu is, resulteert in een fout. Dus laten we het implementeren is_from_google () functie:

openbare functie is_from_google () return strpos ($ _SERVER ['HTTP_REFERER'], 'google.com')> 0;  // end is_from_twitter

En nu zou de test moeten slagen. Maar nogmaals, we moeten compleet zijn, dus laten we de fouttest schrijven om aan te nemen dat de functie niet waar zal worden als gebruikers ergens anders vandaan komen:

function testIsNotComingFromGoogle () // Spoofing de HTTP_REFERER voor doeleinden van deze test en de bijbehorende blogpost $ _SERVER ['HTTP_REFERER'] = 'http://facebook.com'; $ this-> assertFalse ($ this-> plugin-> is_from_google (), 'is_from_google () zal true retourneren wanneer de verwijzende site Google is.');  // end testIsNotComingFromGoogle

Voer tot slot uw tests uit. Het toestaan ​​van al het andere is correct, je zou zes voorbijgaande testen moeten hebben.

Alles samen trekken

Op dit moment hebben we alles wat we nodig hebben om aangepaste welkomstberichten te laten zien aan onze gebruikers. Het enige is dat we onze eerste test die controleert op 'TEST CONTENT' moeten refactoren. Nu moeten we tests uitvoeren voor de volgende gevallen:

  • Wanneer de gebruiker van Twitter komt, zeggen we: "Welkom bij Twitter!"
  • Wanneer de gebruiker van Google komt, zeggen we 'Welkom bij Google!'
  • Wanneer de gebruiker ergens anders komt, gaan we niets vooraf.

Dus laten we de test verwijderen die we eerder hebben gemaakt testAddWelcomeMessage in plaats van drie nieuwe tests toe te voegen.

Eerst voegen we een test toe die het Twitter-welkomstbericht controleert.

In de plug-in verminderen we de add_welcome_message hieraan:

openbare functie add_welcome_message ($ content) return $ content;  // end add_welcome_message

En we voegen eerst de Twitter-test toe:

function testDisplayTwitterWelcome () // Spoof de HTTP_REFERER voor Twitter $ _SERVER ['HTTP_REFERER'] = 'http://twitter.com'; $ this-> assertContains ('Welcome from Twitter!', $ this-> plugin-> add_welcome_message ('Dit is een voorbeeld van een post-inhoud.) Dit simuleert dat WordPress zou terugkeren bij het bekijken van een blogpost.'), 'add_welcome_message () is welkom bericht naar de inhoud van het bericht. ');  // end testDisplayTwitterWelcome

Op dit punt is dit oude hoed, toch? Voer het uit, de test zal mislukken. Implementeer de add_welcome_message om er zo uit te zien:

openbare functie add_welcome_message ($ content) if ($ this-> is_from_twitter ()) $ content = 'Welkom bij Twitter!' . $ Inhoud;  // einde als return $ inhoud;  // end add_welcome_message

Voer het opnieuw uit en het zal slagen. De volgende is de Google-test:

function testDisplayGoogleWelcome () // Spoof de HTTP_REFERER voor Google $ _SERVER ['HTTP_REFERER'] = 'http://google.com'; $ this-> assertContains ('Welcome from Google!', $ this-> plugin-> add_welcome_message ('Dit is een voorbeeld van een post-inhoud.) Dit simuleert dat WordPress zou terugkeren bij het bekijken van een blogpost.'), 'add_welcome_message () is welkom bericht naar de inhoud van het bericht. ');  // end testDisplayGoogleWelcome

Voer de test uit, laat deze mislukken en werk de update vervolgens bij add_welcome_message in de plug-in om een ​​vinkje te plaatsen met behulp van de helperfunctie die we eerder schreven:

openbare functie add_welcome_message ($ content) if ($ this-> is_from_twitter ()) $ content = 'Welkom bij Twitter!' . $ Inhoud;  else if ($ this-> is_from_google ()) $ content = 'Welkom bij Google!' . $ Inhoud;  // einde als return $ inhoud;  // end add_welcome_message

Op dit moment zou u een volledig functionele plug-in moeten hebben die zeven tests met doorlopende eenheden bevat!


Conclusie

Zoals u kunt zien, introduceert unit testing een extra niveau van ontwikkeling, maar kan het aanzienlijk worden terugbetaald in onderhoudbare, goed georganiseerde en toetsbare code. Naarmate uw toepassing groeit, kunt u doorlopend testen uitvoeren om te controleren of uw projecten werken zoals verwacht. Dit is natuurlijk maar een klein voorbeeld van hoe eenheidstesten werken. Het toepassen van deze praktijken kan zijn vruchten afwerpen in veel grotere en / of ingewikkelde projecten.

Ten slotte kunt u deze plug-in, de WordPress-tests en de Hello Reader-unit testen vinden die volledig zijn becommentarieerd op GitHub.