![]() |
|
The symfony CookbookUnit Testen van je Models |
|
You are currently reading "The symfony Cookbook" which is licensed under the Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License license.

|
This work is licensed under a
Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License.
Translation of this work into another language is explicitly allowed. |
Het schrijven van unit tests voor je Propel of Doctrine model is erg makkelijk. In deze tutorial zal een aantal goede tips en best practices vinden om betere tests te schrijven voor je models.
Om een Propel model class te testen, heb je een database nodig. Je hebt er al een voor je ontwikkelomgeving, maar het is altijd een goede eigenschap om een aparte speciaal voor je tests te maken.
Omdat alle tests draaien onder de test omgeving, hoeven we alleen maar de
config/databases.yml te wijzigen en de standaard instellingen voor de test
omgeving te overschrijven:
test:
propel:
param:
dsn: mysql:dbname=myproject_test;host=localhost
dev:
# dev configuration
all:
propel:
class: sfPropelDatabase
param:
dsn: mysql:dbname=myproject;host=localhost
username: someuser
password: somepa$$word
encoding: utf8
persistent: true
pooling: true
classname: PropelPDO
In dit geval hebben we alleen de database naam aangepast, maar je kan ook bijvoorbeeld de database engine aanpassen en SQLite gebruiken.
Nu dat we de database hebben geconfigureerd, kunnen we de tabellen aanmaken door gebruik
te maken van de propel:insert-sql task:
$ php symfony propel:insert-sql --env=test
Nu we een aparte database hebben voor onze tests, hebben we een manier nodig om test gegevens (fixtures) te laden elke keer als we de unit tests starten. Dit is nodig omdat we de database iedere keer in dezelfde staat willen hebben om onze tests te doen.
Dit is erg handig met dank aan de sfDataclass:
$loader = new sfPropelData(); $loader->loadData(sfConfig::get('sf_test_dir').'/fixtures');
De loadData() methode verwacht een directory of bestand als eerste argument.
Een veelvoorkomende fixtures directory ziet er uit als:
test/
fixtures/
10_categories.yml
20_articles.yml
30_comments.yml
Let vooral op de nummers die aan het begin van de bestandsnamen staan. Dit is een simpele manier om de volgorde te bepalen van het inladen van de gegevens. Later in het project, als we ergens een fixture bestand tussen moeten zetten, is het handiger als er nog wat ruimte is tussen de bestaande bestanden:
test/
fixtures/
10_categories.yml
15_must_be_laoded_between_categories_and_articles.yml
20_articles.yml
30_comments.yml
Oplettende lezers zullen hebben opgemerkt dat we de fixtures directory in de test/
directory hebben geplaatst, waar het symfony boek adviseert om deze in de data/
directory te plaatsen. Dit is meer een persoonlijke voorkeur, maar ik hou er van om
mijn fixtures in deze twee directories te organiseren omdat ze dan kunnen worden
gecategoriseerd in twee groepen:
data/fixtures: bevat alle initiele gegevens die nodig zijn om de applicatie
te laten werkentest/fixtures: bevat alle gegevens die nodig zijn om te testen (unit en
functioneel)Dit simpele schema werkt prima wanneer je een kleine set test data hebt, maar wanneer je model groeit, heb je een stuk meer fixtures, en is de tijd om de gegevens te laden steeds groter. We moeten daarom een manier hebben om alleen een subset van de testdata te laden. Een manier om dit te doen is door subcategorien in te voeren voor je testgegevens door het aanmaken van een sub-directory per feature:
test/
fixtures/
10_cms/
10_categories.yml
20_articles.yml
30_comments.yml
20_forum/
10_threads.yml
In plaats van het laden van de hele fixtures directory, kunnen we nu alleen een
van de subdirectories laden, afhankelijk van de model class die je wil testen. In de
meeste gevallen moet je echter ook wat gedeelde gegevens laden, zoals gebruikers:
test/
fixtures/
00_common/
10_users.yml
10_cms/
10_categories.yml
20_articles.yml
30_comments.yml
20_forum/
10_threads.yml
Om het makkelijker te maken dit te doen, accepteert de loadData() methode
een array van directories en/of bestanden:
// laad gebruikers en alle CMS gegevens $loader = new sfPropelData(); $loader->loadData(array( sfConfig::get('sf_test_dir').'/fixtures/00_common/10_users.yml', sfConfig::get('sf_test_dir').'/fixtures/10_cms', ));
Dit zal de 10_users.yml fixtures laden, en daarna alle fixtures die in de 10_cms
directory worden gevonden.
Nu we een aparte database hebben en een manier om onze database in een van te voren
bepaalde staat te krijgen, kunnen we een unit test gaan maken voor het Article model.
Here is een typisch Propel unit test bootstrapping bestand:
// test/unit/model/ArticlePeerTest.php include(dirname(__FILE__).'/../../bootstrap/unit.php'); $configuration = ProjectConfiguration::getApplicationConfiguration('frontend', 'test', true); new sfDatabaseManager($configuration); $loader = new sfPropelData(); $loader->loadData(sfConfig::get('sf_test_dir').'/fixtures'); $t = new lime_test(1, new lime_output_color()); $t->diag('::retrieveBySlug()'); $article = ArticlePeer::retrieveBySlug('the-best-framework-ever'); $t->is($article->getTitle(), 'The Best Framework Ever', '->retrieveBySlug() returns the article that matches the given slug');
Dit script legt zichzelf eigenlijk uit:
Net als iedere andere unit test, includen we ook hier het bootstrap bestand
include(dirname(__FILE__).'/../../bootstrap/unit.php');
We maken het configuratie object aan voor de test omgeving en zetten debugging aan:
$configuration = ProjectConfiguration::getApplicationConfiguration('frontend', 'test', true);
Dit zal ook het autoloaden van Propel classes initialiseren.
We maken de database manager aan. Dit initialiseert de Propel verbinding door
het laden van het databases.yml configuratie bestand:
new sfDatabaseManager($configuration);
We laden onze test data met sfPropelData:
$loader = new sfPropelData(); $loader->loadData(sfConfig::get('sf_test_dir').'/fixtures');
Nu alles klaar staat, kunnen we beginnen met het testen van ons model object.
Wanneer je niet gewend bent aan het schrijven van unit tests, kan dit in het begin nogal intimiderend zijn.
Hier zijn een aantal tips die ik regelmatig gebruik om te bepalen wat te testen:
Mijn test bestanden hebben altijd dezelfde structuur:
// Geef een bericht weer met welke methode je test (-> voor instantie methodes, en :: voor statische methodes) $t->diag('->methodName()'); // test 1 ding tegelijk die in een simpele regel kan worden samengevat // De regel begint altijd met de methode naam // en vervolgens een werkwoord dat uitdrukt wat er moet gebeuren, hoe het zich moet gedragen, ... $t->is($object->methodName(), 1, '->methodName() returns 1 if you pass no argument');
Wanneer je tests schrijft is het makkelijk om een bepaalde situatie in complexe code te vergeten.
symfony 1.2 komt met een handige task om je code coverage te testen, test:coverage.
Dus, nadat mijn tests zijn geschreven voor een bepaalde class, start ik altijd de
test:coverage task om er zeker van te zijn dat ik alles getest heb:
$ php symfony test:coverage test/unit/model/ArticleTest.php lib/model/Article.php
Het eerste argument is een test bestand of een test directory. De tweede is een bestand of directory waarvoor ik de code coverage wil weten.
Als je wil weten welke regels niet worden gedekt, kan je simpelweg de --detailed
optie meegeven:
$ php symfony test:coverage --detailed test/unit/model/ArticleTest.php lib/model/Article.php
If you find a typo or an error, please register and open a ticket.
If you need support or have a technical question, please post to the official user mailing-list.