The symfony Cookbook

Unit Testen van je Models

You are currently browsing
the website for symfony 1

Visit the Symfony2 website


About

You are currently reading "The symfony Cookbook" which is licensed under the Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License license.

Master symfony

Be trained by SensioLabs experts (2 to 6 day sessions -- French or English).
trainings.sensiolabs.com

Books on symfony

Learn more about symfony with the official guides.
books.sensiolabs.com

L'audit Qualité par SensioLabs

200 points de contrôle de votre applicatif web.
audit.sensiolabs.com

Chapter Content

Database Configuratie

Test Gegevens

Het schrijven van Unit Tests

Code coverage

symfony training
Be trained by symfony experts
May 29: Paris (Web Development with Symfony2 - Français)
May 31: Paris (Mastering Symfony2 - Français)
Jun 06: Paris (Introduction to Symfony2 - Français)
Jun 06: Paris (Introduction to Symfony2 - English)
Jun 06: Paris (Going Further with Symfony2 - English)
and more...

Search


powered by google
You are currently browsing "The symfony Cookbook" in Dutch for the 1.2 version - Switch to version: - Switch to language:
Creative Commons 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.
This version of symfony is not maintained anymore.
If some of your projects still use this version, consider upgrading as soon as possible.

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.

Database Configuratie

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

Test Gegevens

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:

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.

Het schrijven van Unit Tests

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:

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');

Code coverage

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

Questions & Feedback

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.