Programmeren met Yii2 automatisch testen met codeceptie

Wat je gaat creëren

Als je vraagt: "Wat is Yii?" bekijk mijn eerdere tutorial, Introductie tot het Yii Framework, die de voordelen van Yii bekijkt en een overzicht bevat van wat er nieuw is in Yii 2.0, uitgebracht in oktober 2014.

In deze serie Programming With Yii2 begeleid ik lezers in gebruik van het Yii2 Framework voor PHP. In deze zelfstudie zal ik geautomatiseerd testen met behulp van Codeception, dat is geïntegreerd met het Yii2-ontwikkelingsraamwerk, verkennen.

Toegegeven, mijn ervaring met het schrijven van tests met mijn code is schaars. Ik heb vaak deel uitgemaakt van solo- of kleine projecten met beperkte middelen. Tijdens mijn tijd bij Microsoft hadden we verschillende testteams die dit deden. Maar eerlijk gezegd is dit waarschijnlijk ook typerend voor jou, toch? Programmeurs vinden het leuk om te coderen, ze schrijven geen tests - tenminste, oude-schoolprogrammeurs niet.

Codeception is een innovatieve bibliotheek die het schrijven van toetsen letterlijk leuk en gemakkelijk maakt. En ik zou zeggen dat ze in redelijke mate geslaagd zijn. Toen ik mijn teen in het water van 'Lake Codeception' doopte, was het meestal gemakkelijk en leuk. Toen ik echter dieper begon te werken, kreeg ik configuratieproblemen met Yii en de specifieke modules die in deze serie werden gebruikt. Er waren zeker uitdagingen. Over het algemeen ben ik echter onder de indruk en zie ik het voordeel van meer leren.

Eenvoudig gezegd zorgt Codeception en de integratie ervan met Yii ervoor dat ik meer tests wil schrijven, een primeur voor mij. Ik vermoed dat je een vergelijkbare ervaring zult hebben. 

Een kleine herinnering voordat we aan de slag gaan, ik neem wel deel aan de onderstaande commentaarthreads. Ik ben vooral geïnteresseerd als u aanvullende ideeën heeft of onderwerpen wilt voorstellen voor toekomstige zelfstudies. Als u een vraag of een suggestie voor een onderwerp heeft, kunt u hieronder berichten plaatsen. Je kunt me ook rechtstreeks op Twitter @reifman bereiken.

Ermee beginnen

Installatie van Codeception

Om mij te helpen, gebruikte ik Yii's Testing Environment Setup-documentatie. Ik begon met een wereldwijde installatie van codering, zodat ik het vanuit elk project kon gebruiken.

$ composer global vereist "codeception / codeception = 2.1. *" Gewijzigde huidige map naar /Users/Jeff/.composer ./composer.json is bijgewerkt. Het laden van composer-repositories met pakketinformatie Het bijwerken van afhankelijkheden (inclusief require-dev) - Symfony installeren / yaml (v3.1.1) Bezig met laden van cache ... codeception / codeception suggereert het installeren van symfony / phpunit-bridge (voor ondersteuning van phpunit-bridge) Schrijfslotbestand Autoload-bestanden genereren

Je moet ook eisen codeception / specificeren:

$ composer global vereist "codeception / specificeren = *" Gewijzigde huidige map naar /Users/Jeff/.composer ./composer.json is bijgewerkt Het laden van composer-repositories met pakketinformatie Het bijwerken van afhankelijkheden (inclusief require-dev) composer vereist "codeception / verify = * "- Codeception installeren / specificeren (0.4.3) Downloaden: 100% Schrijfslotbestand Autoloadbestanden genereren

En codeception / controleren:

$ composer vereist "codeception / verify = *" ./composer.json is bijgewerkt Het laden van composer-repositories met pakketinformatie Bijwerken van afhankelijkheden (inclusief require-dev) - Installeren van codeception / verify (0.3.0) Downloaden: 100% Schrijfslotbestand Genereren autoload bestanden

Vervolgens helpt het om een ​​alias in te stellen codecept met behulp van uw globale composer-directory:

$ composer global status Gewijzigde huidige map naar /Users/Jeff/.composer Geen lokale wijzigingen 

Hiermee wordt de alias ingesteld:

$ alias codecept = "/ Users / Jeff / .composer / vendor / bin / codecept"

Yii vereist ook dat je Faker installeert, wat valse testgegevens genereert voor je applicatie:

$ composer vereist --dev yiisoft / yii2-faker: * ./composer.json is bijgewerkt. Laden van composer-repositories met pakketinformatie. Updaten van afhankelijkheden (inclusief require-dev). Niets te installeren of updaten. Autoload bestanden genereren.

Codenceptie instellen met uw applicatie

Codecept bootstrapinitialiseert codering voor uw Yii-toepassing en maakt een verscheidenheid aan configuratiebestanden voor het bouwen en uitvoeren van tests tegen uw toepassing. We gebruiken de Hello-applicatie uit deze serie voor deze tutorial. Zie de GitHub-link op deze pagina voor de code.

$ codecept bootstrap Initialiseren van Codeception in / Gebruikers / Jeff / Sites / hello Filecodeception.yml gemaakt <- global configuration tests/unit created <- unit tests tests/unit.suite.yml written <- unit tests suite configuration tests/functional created <- functional tests tests/functional.suite.yml written <- functional tests suite configuration tests/acceptance created <- acceptance tests tests/acceptance.suite.yml written <- acceptance tests suite configuration tests/_output was added to .gitignore --- tests/_bootstrap.php written <- global bootstrap file Building initial Tester classes Building Actor classes for suites: acceptance, functional, unit -> AcceptanceTesterActions.php is met succes gegenereerd. 0 methoden toegevoegd \ AcceptanceTester bevat modules: PhpBrowser, \ Helper \ Acceptatie AcceptanceTester.php gemaakt. -> FunctionalTesterActions.php succesvol gegenereerd. 0 methoden toegevoegd \ FunctionalTester bevat modules: \ Helper \ Functional FunctionalTester.php gemaakt. -> UnitTesterActions.php succesvol gegenereerd. 0 methoden toegevoegd \ UnitTester bevat modules: Asserts, \ Helper \ Unit UnitTester.php gemaakt. Bootstrap is klaar. Bekijk / Users / Jeff / Sites / hello / tests directory

Om de een of andere reden eindigde ik ook met dubbele testmappen in hallo / tests; gewoon het verwijderen van hallo / tests / functioneel, hallo / tests / acceptatie, en hallo / tests / eenheid opgeruimd dingen. Alle tests leven in hallo / tests / codeception / *.

De verschillende soorten tests

Codeception is gericht op drie soorten tests:

  1. Het testen van eenheden controleert of specifieke eenheden werken, zoals een uitgebreide test van alle methoden van uw model.
  2. Functioneel testen verifieert algemene toepassingsscenario's alsof een gebruiker ze uitvoert, maar met behulp van webbrowseremulatie.
  3. Acceptatietests zijn identiek aan functionele tests, maar voeren de tests feitelijk uit via een webbrowser.

En het ondersteunt drie verschillende soorten testformaten voor uw testcode:

  1. Cept: het is het eenvoudigste testbestand met één scenario
  2. Cest: een objectgeoriënteerde indeling voor het uitvoeren van meerdere tests binnen één bestand
  3. Test: tests geschreven op PHPUnit, een PHP-testraamwerk

Laten we beginnen met een voorbeeld van acceptatietests gebruik makend van cept formaat:

Acceptatietests

We zullen Codecept's gebruiken WelkomTest eerst het voorbeeld.

$ codecept genereren: cept acceptatie Welkomsttest is gemaakt in /Users/Jeff/Sites/hello/tests/acceptance/WelcomeCept.php

Dit genereert test / acceptatie / WelcomeCept.php, die we hieronder zullen bewerken.

Aangezien acceptatietests de browser vereisen, moeten we /tests/acceptance.suite.yml in ons project aanpassen om onze ontwikkelings-URL te leveren, http: // localhost: 8888 / hello:

# Codeception Test Suite-configuratie # # Suite voor acceptatietests. # Voer tests uit in de browser met behulp van de WebDriver of PhpBrowser. # Als u zowel WebDriver- als PHPBrowser-tests nodig hebt, maakt u een afzonderlijke suite. class_name: AcceptanceTester-modules: ingeschakeld: - PhpBrowser: url: http: // localhost: 8888 / hallo / - \ Helper \ Acceptatie 

Nu zijn we klaar om de eerste test in tests / acceptatie / WelcomeCept.php te wijzigen. Ik schrijf een test die de voorpagina laadt om ervoor te zorgen dat deze werkt zoals verwacht. 

Codeceptietests hebben in dit geval het concept van een actor, $ I = nieuwe AcceptanceTester ().

Hier leest u hoe actoren worden beschreven in de documentatie van Codeception:

We hebben een UnitTester, die functies uitvoert en de code test. We hebben ook een FunctionalTester, een gekwalificeerde tester, die de toepassing als geheel test, met kennis van de interne functies. En een AcceptanceTester, een gebruiker die met onze applicatie werkt via een interface die wij bieden.

U kunt uw tests becommentariëren met code, zoals $ I-> wantTo ('voer een bepaalde test uit')of 'zorg ervoor dat de voorpagina werkt'.

In mijn test wil ik het zien $ I-> zie tekst voor 'Gefeliciteerd!' en 'Yii-powered':

wantTo ('zorg dat frontpage werkt'); $ I-> amOnPage ( '/'); $ I-> zie ( 'Gefeliciteerd!'); $ I-> zie ( 'Yii-powered'); 

Dit is de huidige Hello-startpagina:

Laten we vervolgens de test gewoon uitvoeren codecept uitvoeren:

$ codecept run Codeception PHP Testing Framework v2.1.11 Powered by PHPUnit 5.3.5 door Sebastian Bergmann en medewerkers. Acceptatietests (1) --------------------------------------------- ------------------------------------------ Zorg dat de voorpagina werkt (WelcomeCept) Ok -------------------------------------------------- -------------------------------------------------- -------- Functionele testen (0) ------------------------ ------------- -------------------------------- Unit Tests (0) ------------- ----------------- --------------------------------- ------------ Tijd: 554 ms, geheugen: 10.25MB OK (1 test, 2 asserties)

Zoals u kunt zien, is onze test geslaagd en was de code om deze functionaliteit te verifiëren vrij leesbaar en eenvoudig.

Opmerkingen over de standaardtests van Yii

Om verder te gaan, begon ik de standaardtests van Yii te gebruiken. Op dit punt kwam ik een aantal configuratieproblemen tegen, vooral door het gebruik van de aangepaste yii2-gebruikersmodule in deze serie. Anderen waren te wijten aan kleine bugs met Yii, waarmee het team snel heeft gereageerd en opgelost toen het werd gerapporteerd op GitHub; in sommige gevallen waren problemen opgelost in latere versies van de yii2-basisboom.

Omdat ik de yii2-basisstructuur voor deze serie had bijgewerkt, moest ik ook enkele standaardtests wijzigen.

Hier is een voorbeeld van de uitvoer voor het uitvoeren van de standaard acceptatietests nadat ik een paar kleine aanpassingen had aangebracht:

$ codecept run Codeception PHP Testing Framework v2.1.11 Powered by PHPUnit 5.3.5 door Sebastian Bergmann en medewerkers. Acceptatietests (4) --------------------------------------------- -------------------------------------------------- - Zorg ervoor dat over werken werkt (AboutCept) Ok Zorg ervoor dat contact werkt (ContactCept) Ok Zorg ervoor dat de startpagina werkt (HomeCept) Ok Controleer of de aanmelding werkt (LoginCept) Ok ----------------------------------------------------------------------------------------------------------------------

Functioneel testen

Om functionele tests te laten werken, moest ik een exemplaar van de ingebouwde server van Yii draaien. Ik had niets over dit onderdeel geweten totdat Yii's Alex Makarov het in onze GitHub-uitwisseling noemde.

$ ./yii dienen

Ik heb kleine wijzigingen aangebracht in de functionele tests in / tests / codeception / functioneel, meestal om te zoeken naar mijn specifieke bijgewerkte tekstreeksen, d.w.z. "Ongeldige login of wachtwoord" in plaats van Yii's standaard. Hier is een kijkje op LoginCept.php:

wantTo ('zorg dat login werkt'); $ loginPage = LoginPage :: openBy ($ I); $ I-> zie ( 'Login'); $ I-> amGoingTo ('probeer in te loggen met lege inloggegevens'); $ LoginPage-> login ( ""); $ I-> expectTo ('zie validatiefouten'); $ I-> zie ('Aanmelden mag niet leeg zijn.'); $ I-> zie ('Wachtwoord mag niet leeg zijn'); $ I-> amGoingTo ('probeer in te loggen met verkeerde inloggegevens'); $ loginPage-> login ('admin', 'fout'); $ I-> expectTo ('zie validatiefouten'); $ I-> zie ('Ongeldige login of wachtwoord'); $ I-> amGoingTo ('probeer in te loggen met de juiste inloggegevens'); $ loginPage-> login ('admin', 'admin11'); $ I-> expectTo ('zie gebruikersinfo'); $ I-> zie ( 'Logout');

Kortom, de code benadert de Login formulier model en test de verschillende methoden met Yii serve.

Dit is de testcode van /tests/codeception_pages/LoginPage.php die door hem wordt gebruikt (ik moest deze ook aanpassen voor wijzigingen die we in de reeks hebben aangebracht):

class LoginPage breidt BasePage uit public $ route = 'user / login'; / ** * @param string $ gebruikersnaam * @param string $ wachtwoord * / publieke functie login ($ gebruikersnaam, $ wachtwoord) $ this-> actor-> fillField ('input [naam = "login-formulier [login]" ] ', $ gebruikersnaam); $ this-> actor-> fillField ('input [name = "login-form [wachtwoord]"]', $ wachtwoord); $ This-> actor-> klik ( 'knop [type = submit]');  

Je kunt zien dat we de acteur coderen fillFieldsen Klik knoppen voor onze bijgewerkte formuliervelden. 

Bij het oplossen van problemen met mijn Codeception-integratie met Yii, vond ik het nuttig om deze tests uit te voeren in de uitgebreide modus:

$ codecept run -vvv

Dit is de uitgebreide uitvoer van de functionele login-tests in MacOS Terminal, GESLAAGD en MISLUKT zijn kleurgecodeerd rood of roze en omgekeerd voor zichtbaarheid:

Functionele testen (4) --------------------------------------------- -------------------------------------------------- - Modules: bestandssysteem, Yii2 ... ------------------------------------------ -------------------------------------------------- -------------------------- Zorg ervoor dat inloggen werkt (LoginCept) Scenario: * Ik ben op pagina "/index-test.php/user/ login "[Pagina] /index-test.php/user/login [Response] 200 [Request Cookies] [] [Response Headers] " content-type ": [" text / html; charset = UTF-8 "] * Ik zie "Login" * Ik ga proberen in te loggen met lege inloggegevens * Ik vul veld "invoer [naam =" login-formulier [login] "]", "" * Ik vul veld "invoer [naam =" login -vorm [wachtwoord] "]", "" * Ik klik op "-knop [type = submit]" [Uri] http: //localhost/index-test.php/user/login [Method] POST [Parameters] "_csrf ":" VEpvcmk3bVgFH1Y9AVsmYWQQDEouTSggYXMFGStdKBEnCyQfBxo8Bw == "," login-formulier [login] ":" "," login-formulier [wachtwoord] ":" " [Pagina] http: //localhost/index-test.php/user/login [Response] 200 [Request Cookies] "_csrf": "dd395a9e5e3c08 cfb1615dae5fc7b5ba0a2025c003e430ba0139b300f4a917ada: 2: i: 0; s: 5: "_ csrf"; i: 1; s: 32: "QU9OhlK90Zc8GzEx59jkBjEIsAKmn-Q_"; " [Response Headers] " content-type ": [" text / html ; charset = UTF-8 "] * Ik verwacht validatiefouten te zien * Ik zie" Login mag niet leeg zijn. "* Ik zie" Wachtwoord mag niet leeg zijn. "* Ik ga proberen in te loggen met verkeerde referenties * Ik vul veld in "input [naam =" login-formulier [login] "]", "admin" * Ik vul veld "invoer [naam =" login-formulier [wachtwoord] "]", "fout" * Ik klik "knop [type = submit] "[Uri] http: //localhost/index-test.php/user/login [Method] POST [Parameters] " _csrf ":" QjFBRl9hMjMTZHgJNw15CnJrIn4YG3dLdwgrLR0Ld3oxcAorMUxjbA == "," login-formulier [login] ":" admin "," login-formulier [wachtwoord] ":" wrong " [Pagina] http: //localhost/index-test.php/user/login [Response] 200 [Request Cookies] " _csrf ":" dd395a9e5e3c08cfb1615dae5fc7b5ba0a2025c003e430ba0139b300f4a917ada: 2 : i: 0; s: 5: "_ csrf"; i: 1; s: 32: "QU9OhlK90Zc8GzEx59jkBjEIsAKmn-Q_"; " [Response Headers] " content-type ": [" text / html; charset = UTF-8 "] * Ik verwacht validatiefouten te zien * Ik zie" Ongeldige login of wachtwoord "* Ik ga proberen in te loggen met de juiste inloggegevens * I fill field" input [name = "login-form [login ] "]", "admin" * Ik vul veld "invoer [naam =" login-formulier [wachtwoord] "]", "admin11" * Ik klik "knop [type = submit]" [Uri] http: // localhost /index-test.php/user/login [Methode] POST [Parameters] "_csrf": "bG8uMXdPYk49Ohd.HyMpd1w1TQkwNSc2WVZEWjUlJwcfLmVcGWIzEQ ==", "login-formulier [login]": "admin", "login-formulier [wachtwoord] ":" admin11 " [Headers] " location ": [" http: //localhost/index-test.php "]," content-type ": [" text / html; charset = UTF-8 "] [Pagina] http: //localhost/index-test.php/user/login [Response] 302 [Request Cookies] " _csrf ":" dd395a9e5e3c08cfb1615dae5fc7b5ba0a2025c003e430ba0139b300f4a917ada: 2: i: 0; s : 5: "_ csrf"; i: 1; s: 32: "QU9OhlK90Zc8GzEx59jkBjEIsAKmn-Q_"; " [Response Headers] " location ": [" http: //localhost/index-test.php "]," content-type ": [" text / html; charset = UTF-8 "] [Doorverwijzen naar] http: //localhost/index-test.php [Pagina] http: //localhost/index-test.php [Response] 200 [Request Cookies] " _csrf ": "dd395a9e5e3c08cfb1615dae5fc7b5ba0a2025c003e430ba0139b300f4a917ada: 2: i: 0; s: 5:" _ csrf "; i: 1; s: 32:" QU9OhlK90Zc8GzEx59jkBjEIsAKmn-Q_ ";" [Response Headers] "content-type": ["text / html; charset = UTF-8 "] * Ik verwacht gebruikersinformatie te zien * Ik zie" Afmelden "PASSED 

Over het algemeen is er een beetje te leren om aan de slag te gaan met Codeception en uw tests correct te coderen. Maar de resultaten zijn indrukwekkend en nuttig.

Testen van een eenheid

Kort gezegd, unit tests zijn programmatisch testen van onze infrastructuur en modellen. Idealiter zouden we tests schrijven voor elke methode en gebruiksvariatie van onze modellen.

Helaas kon ik geen unit tests laten werken in onze boom vanwege kleine Yii-bugs die nog moeten worden vrijgegeven of configuratieproblemen tussen Codeception en yii2-gebruiker die we hebben geïntegreerd in How to Program With Yii2: Integrating User Registration. 

Eenheidstests (3) --------------------------------------------- -------------------------------------------------- ----- Modules: ------------------------------------------- -------------------------------------------------- ---------------------- Proberen om login geen gebruiker te testen (tests \ codeception \ eenheid \ modellen \ LoginFormTest :: testLoginNoUser) ... 
PHP Fatale fout 'yii \ base \ ErrorException' met bericht 'Aanroep voor niet-gedefinieerde functietests \ codering \ eenheid \ modellen \ verwachten ()' 

Ik zal eenheidstests opnieuw behandelen in onze opstartreeks die geen gebruik maakt van de yii2-gebruiker, maar in plaats daarvan de ingebouwde gebruikersintegratie van de geavanceerde boom van de Yii gebruikt..

Laten we een paar voorbeelden van de Yii2-app-basisboom bekijken.

Contactformulier e-mails testen

De hello / tests / codeception / unit / models / ContactFormTest.php test het verzenden van een e-mail door programmatisch gebruik van modellen:

mailer-> fileTransportCallback = function ($ mailer, $ message) return 'testing_message.eml'; ;  beschermde functie tearDown () unlink ($ this-> getMessageFile ()); ouder :: TearDown ();  openbare functie testContact () $ model = $ this-> createMock ('app \ models \ ContactForm', ['validate']); $ Model-> verwacht ($ this-> eenmaal ()) -> methode ( 'valideren') -> zal ($ this-> returnValue (true)); $ model-> attributes = ['name' => 'Tester', 'email' => '[email protected]', 'subject' => 'zeer belangrijk letteronderwerp', 'body' => 'hoofdtekst bericht ',]; $ Model-> contact ('[email protected] '); $ this-> specificeren ('email should be send', function () expect ('email file should exist already', file_exists ($ this-> getMessageFile ())) -> true ();); $ this-> specificeren ('message should contain correcte data', function () gebruik ($ model) $ emailMessage = file_get_contents ($ this-> getMessageFile ()); expect ('email should contain username', $ emailMessage) -> bevat ($ model-> naam); verwacht ('e-mail moet afzender email bevatten', $ emailMessage) -> bevat ($ model-> email); verwacht ('e-mail moet onderwerp bevatten', $ emailMessage) -> bevat ($ model-> onderwerp); verwacht ('email moet body bevatten', $ emailMessage) -> bevat ($ model-> body););  private functie getMessageFile () return Yii :: getAlias ​​(Yii :: $ app-> mailer-> fileTransportPath). '/Testing_message.eml';  

Ik kon deze test niet succesvol doorstaan ​​vanwege een kleine fout in Yii die nog niet is bijgewerkt (of ik kon de bijgewerkte code tenminste niet vinden). Mijn druppel van de Yii-codebasis was de naamgeving van uitgaande e-mail met datumstempels en de bovenstaande code was op zoek naar een vaste bestandsnaam. Dus het is altijd mislukt. Toch is het handig om te zien hoe programmatische tests modellen kunnen gebruiken om een ​​bestand te genereren en vervolgens naar dat bestand te zoeken en de inhoud ervan te valideren om te controleren of die code werkt.

Inloggen testen

Laten we kijken naar hallo / tests / codeception / unit / models / LoginFormTest.php. Nogmaals, mijn gebruik van de yii2-gebruiker maakte het overdreven moeilijk om te integreren op het moment dat deze tutorial werd geschreven; we kunnen echter kijken naar de conceptuele benadering van het testen van gebruikersmodelfuncties.

hier is testLoginCorrect (), die kijkt of login lukt met een correct wachtwoord:

public function testLoginCorrect () $ model = nieuw LoginForm (['gebruikersnaam' => 'admin', 'password' => 'admin11',]); $ this-> specificeren ('gebruiker moet in staat zijn om in te loggen met de juiste inloggegevens', functie () gebruik ($ model) verwacht ('model moet inloggen gebruiker', $ model-> login ()) -> true (); verwachten ('foutmelding moet niet worden ingesteld', $ model-> fouten) -> hasntKey ('wachtwoord'); verwacht ('gebruiker moet ingelogd zijn', Yii :: $ app-> gebruiker-> isGuest) -> false ();); 

Het gebruikt de Login formulier model om de gebruiker programmatisch in te loggen, en dan kijkt het programmatisch om te zien of de huidige gebruiker van Yii nu geen gast meer is.

verwachten ('gebruiker moet ingelogd zijn', Yii :: $ app-> gebruiker-> isGuest) -> false ();

Wat is het volgende?

Ik hoop dat je het leuk vond om te leren over Codeception en de integratie ervan met Yii, ondanks enkele obstakels die ik tegenkwam. De standaardinstallatie van yii2-basic zou vandaag beter moeten presteren.

Als u meer wilt weten over wanneer en wat u moet testen en waarom, raad ik u aan het Yii-testoverzicht te lezen. Er is zeker meer te leren over Codeception en meer complete tests te schrijven.

Bekijk de komende tutorials in onze Programming With Yii2-serie terwijl we doorgaan met duiken in verschillende aspecten van het framework. Als je wilt weten wanneer de volgende Yii2-tutorial aankomt, volg me dan @reifman op Twitter of bekijk mijn instructeurpagina. 

Je kunt ook onze Building Your Startup With PHP-serie bekijken, die gebruik maakt van Yii2's geavanceerde sjabloon terwijl we een real-world applicatie bouwen. U kunt de start-upapplicatie, Meeting Planner, vandaag zelfs uitproberen.

Gerelateerde Links

  • Codeception
  • Yii2 Developer Exchange, mijn Yii2-bronsite
  • Yii2 Omgevingstest testen