Test-driven ontwikkeling met Laravel & Doctrine

Als ontwikkelaar van PHP kunt u de TDD-techniek (Test-Driven Development) gebruiken om uw software te ontwikkelen door tests te schrijven. Typisch, TDD verdeelt elke taak van de ontwikkeling in individuele eenheden. Vervolgens wordt een test geschreven om ervoor te zorgen dat de eenheid zich gedraagt ​​zoals verwacht.

Elk project dat gebruikmaakt van Test-Driven Development volgt drie eenvoudige stappen herhaaldelijk:

  • Schrijf een test voor het volgende stukje functionaliteit dat u wilt toevoegen.
  • Schrijf de functionele code totdat de test slaagt.
  • Refactoreer zowel nieuwe als oude code om het goed gestructureerd te maken.

Blijf door deze drie stappen fietsen, één test tegelijk, en bouw de functionaliteit van het systeem op. Testen helpt je om te refactoren, waardoor je je ontwerp in de loop van de tijd kunt verbeteren en sommige ontwerpproblemen duidelijker worden.

De tests die kleine individuele componenten bevatten, worden genoemd unit tests. Hoewel unit tests onafhankelijk kunnen worden uitgevoerd, als u een aantal van de componenten test wanneer ze zijn geïntegreerd met andere componenten, doet u het integratie testen. Het derde soort testen is test stubs. Met teststubs kunt u uw code testen zonder dat u echt naar een database hoeft te bellen.

Waarom TDD werkt

Tegenwoordig, aangezien je de moderne PHP IDE-syntaxis kunt gebruiken, is feedback geen groot probleem. Een van de belangrijke aspecten van uw ontwikkeling is ervoor zorgen dat de code doet wat u ervan verwacht. Omdat software ingewikkeld is (verschillende componenten met elkaar geïntegreerd), zou het moeilijk zijn om al onze verwachtingen waar te maken. Vooral aan het einde van het project zal het project door je ontwikkeling complexer worden en dus moeilijker te debuggen en testen.

TDD controleert of de code doet wat u ervan verwacht. Als er iets misgaat, zijn er slechts een paar regels code om opnieuw te controleren. Fouten zijn gemakkelijk te vinden en op te lossen. In TDD richt de test zich op het gedrag, niet op de implementatie. TDD biedt beproefde code die is getest, ontworpen en gecodeerd.

PHPUnit & Laravel

PHPUnit is de de-facto standaard voor testen van eenheden PHP. Het is in wezen een kader voor het schrijven van tests en het bieden van de hulpmiddelen die u nodig hebt om tests uit te voeren en de resultaten te analyseren. PHPUnit ontleent zijn structuur en functionaliteit aan Kent Beck's SUnit.

Er zijn verschillende beweringen die u kunnen helpen bij het testen van de resultaten van alle soorten oproepen in uw toepassingen. Soms moet je wat creatiever zijn om een ​​complexere stuk functionaliteit te testen, maar de beweringen van PHPUnit bestrijken de meeste gevallen die je zou willen testen. Hier is een lijst van enkele van de meest voorkomende die je tijdens je tests zult gebruiken:

  • AssertTrue: Controleer de invoer om te controleren of deze gelijk is aan waar.
  • AssertFalse: Controleer de invoer om te controleren of deze gelijk is aan de valse waarde.
  • AssertEquals: Controleer het resultaat tegen een andere invoer voor een overeenkomst.
  • AssertArrayHasKey (): Meldt een fout als array niet over de sleutel beschikt.
  • AssertGreaterThan: Controleer het resultaat om te zien of het groter is dan een waarde.
  • AssertContains: Controleer of de invoer een bepaalde waarde bevat.
  • AssertType: Controleer of een variabele van een bepaald type is.
  • AssertNull: Controleer of een variabele nul is.
  • AssertFileExists: Controleer of er een bestand bestaat.
  • AssertRegExp: Controleer de invoer tegen een reguliere expressie.

PHPUnit 4.0 is standaard geïnstalleerd in Laravel en u kunt de volgende opdracht uitvoeren om het bij te werken:

bash composer global vereist "phpunit / phpunit = 5.0. *"

De phpunit.xml bestand in de Laravel-hoofddirectory kunt u enkele configuraties doen. In dit geval, als u de standaardconfiguratie wilt overschrijven, kunt u het bestand bewerken:

"xml

./ Testen / app /

"

Zoals je ziet in de bovenstaande code, heb ik de voorbeelddatabaseconfiguratie toegevoegd (niet gebruikt in het artikel).

Wat is Doctrine ORM?

Doctrine is een ORM die het patroon van de gegevensverwerker implementeert en waarmee u een schone scheiding kunt aanbrengen tussen de bedrijfsregels van de toepassing en de persistentielaag van de database. Om Doctrine op te zetten, is er een brug om toe te voegen aan de bestaande configuratie van Laravel 5. Om Doctrine 2 in ons Laravel-project te installeren, voeren we het volgende commando uit:

bash-componist heeft laravel-doctrine / orm nodig

Zoals gebruikelijk, moet het pakket worden toegevoegd aan de app / config.php, als de dienstverlener:

php LaravelDoctrine \ ORM \ DoctrineServiceProvider :: class,

De alias moet ook worden geconfigureerd:

php 'EntityManager' => LaravelDoctrine \ ORM \ Facades \ EntityManager :: klasse

Ten slotte publiceren we de pakketconfiguratie met:

bash php artisan verkoper: publiceer --tag = "config"

Hoe Doctrine Repositories te testen

Voor alles moet je over armaturen weten. Fixtures worden gebruikt om een ​​gecontroleerde set gegevens in een database te laden, die we nodig hebben om te testen. Gelukkig heeft Doctrine 2 een bibliotheek om je te helpen bij het schrijven van armaturen voor de Doctrine ORM.

Om de armaturenbundel in onze Laravel-app te installeren, moeten we de volgende opdracht uitvoeren:

bash-componist vereist --dev doctrine / doctrine-armaturen-bundel

Laten we onze armatuur inrichten proeven / Fixtures.php:

"php namespace Test; gebruik Doctrine \ Common \ Persistence \ ObjectManager; gebruik Doctrine \ Common \ DataFixtures \ FixtureInterface; gebruik app \ Entity \ Post;

class Fixtures implementeert FixtureInterface / ** * Load the Post-fixtures * @param ObjectManager $ manager * @return void * / public function load (ObjectManager $ manager) $ Post = new Post (['title' => 'hello world' , 'lichaam' => 'dit is lichaam']); $ Manager-> aanhouden ($ Post); $ Manager-> flush ();

"

Zoals je ziet, moet je fixture-klasse het FixtureInterface en zou het moeten hebben laden (ObjectManager $ manager) methode. Doctrine2-fixtures zijn PHP-klassen waarin u objecten kunt maken en deze kunt behouden in de database. Om onze armaturen autoload in Laravel, moeten we wijzigen composer.json in onze Laravel-root:

json ... "autoload-dev": "classmap": ["tests / TestCase.php", "tests / Fixtures.php" // hier toegevoegd], ...

Voer dan uit:

bash composer dump-autoload

Laten we ons testbestand maken in de testdirectory DoctrineTest.php.

"php namespace Test; gebruik App; gebruik App \ Entity \ Post; gebruik Doctrine \ Common \ Data Fixtures \ Executor \ ORMExecutor; gebruik Doctrine \ Common \ DataFixtures \ Purger \ ORMPurger; gebruik Doctrine \ Common \ DataFixtures \ Loader; gebruik App \ Repository \ PostRepo;

class doctrineTest breidt TestCase uit private $ em; privé $ repository; privé $ loader; openbare functie setUp () parent :: setUp (); $ this-> em = App :: make ('Doctrine \ ORM \ EntityManagerInterface'); $ this-> repository = new PostRepo ($ this-> em); $ this-> executor = nieuwe ORMExecutor ($ this-> em, nieuwe ORMPurger); $ this-> loader = new Loader; $ this-> loader-> addFixture (new Fixtures);

/ ** @test * / public function post () $ purger = nieuwe ORMPurger (); $ executor = nieuwe ORMExecutor ($ this-> em, $ purger); $ Executor-> execute ($ this-> loader-> getFixtures ()); $ user = $ this-> repository-> PostOfTitle ('Hello World'); $ This-> EM> clear (); $ this-> assertInstanceOf ('App \ Entity \ Post', $ user);  "

In de opstelling() methode, ik instantiate de ORMExecutor en de lader. We laden ook de Wedstrijden klasse die we zojuist hebben geïmplementeerd.

Vergeet niet dat de /** @test */ annotatie is erg belangrijk, en zonder dit zal de phpunit terugkeren a Geen tests gevonden in de klas fout.

Begin met het uitvoeren van het testen in onze projectroot:

bash sudo phpunit

Het resultaat zou zijn:

"bash PHPUnit 4.6.6 door Sebastian Bergmann en medewerkers.

Configuratie gelezen van /var/www/html/laravel/phpunit.xml. Tijd: 17.06 seconden, geheugen: 16.00M OK (1 test, 1 bewering) "

Als u objecten tussen fixtures wilt delen, is het mogelijk om eenvoudig een verwijzing naar dat object op naam toe te voegen en later te verwijzen om een ​​relatie te vormen. Hier is een voorbeeld:

"php namespace Test; gebruik Doctrine \ Common \ Persistence \ ObjectManager; gebruik Doctrine \ Common \ DataFixtures \ FixtureInterface; gebruik app \ Entity \ Post;

class PostFixtures implementeert FixtureInterface / ** * Load the User-fixtures * * @param ObjectManager $ manager * @return void * / public function load (ObjectManager $ manager) $ postOne = new Post (['title' => 'hallo' , 'lichaam' => 'dit is lichaam']); $ postTwo = new Post (['title' => 'hallo daar', 'body' => 'dit is lichaam twee']); $ Manager-> aanhouden ($ postOne); $ Manager-> aanhouden ($ postTwo); $ Manager-> flush ();

 / / store verwijzing naar beheerdersrol voor gebruikersrelatie naar rol $ this-> addReference ('nieuw bericht', $ postOne);  "

en de opmerkingopname:

"php namespace Test; gebruik Doctrine \ Common \ Persistence \ ObjectManager; gebruik Doctrine \ Common \ DataFixtures \ FixtureInterface; gebruik app \ Entity \ Post;

class CommentFixtures implementeert FixtureInterface / ** * Load de user fixtures * * @param ObjectManager $ manager * @return void * / public function load (ObjectManager $ manager) $ comment = new Comment (['title' => 'hallo' , 'email' => '[email protected]', 'text' => 'mooie post']); $ Comment-> setPost ($ this-> getReference ( 'new-post')); // laad de opgeslagen referentie $ manager-> persist ($ comment); $ Manager-> flush (); // winkelverwijzing naar nieuw bericht voor Reactie-relatie naar bericht $ this-> addReference ('nieuw bericht', $ postOne); "

Met twee methoden van getReference () en setReference (), je kunt objecten tussen fixtures delen.

Als het bestellen van armaturen belangrijk voor je is, kun je ze eenvoudig bestellen met de getOrder methode in je armaturen als volgt:

php public function getOrder () return 5; // nummer in welke volgorde de fixtures worden geladen

Let op de volgorde is relevant voor de Loader-klasse.

Een van de belangrijke dingen over armaturen is hun vermogen om afhankelijkheidsproblemen op te lossen. Het enige dat je moet toevoegen is een methode in je fixture zoals ik hieronder deed:

php public function getDependencies () return array ('Test \ CommentFixtures'); // fixture classes fixture is afhankelijk van

Conclusie

Dit is slechts een beschrijving van Test-Driven Development met Laravel 5 en PHPUnit. Wanneer u repositories test, is het onvermijdelijk dat u de database raakt. In dit geval zijn doctrine-fixtures belangrijk.