Contents
1. DrupalCamp Montreal 2010 slides
simpletest_session_drupalcampmtl2010_2.pdf
2. Sample Module / Exemple de module
Module demo pour/for Drupal 6 mymodule.zip.
Module demo pour/for Drupal 7 simpletest_mymodule_7.zip.
- Dans les deux cas, une lecture rapide de ce module vous sera utile pour comprendre comment un simpletest est formaté. / Both modules are very small and useful to figure out how simpletest works.
3. API
Le API ne semble pas être sur drupal.org. Voici le seul endroit où je l'ai trouvé: http://cwgordon.com/simpletest/doxygen/2008-june/annotated.html
4. Formation Simpletest
Cette page a été créée pour la formation simpletest qui a eu lieu le 9 avril 2010 à 10h chez Koumbit et qui a duré à peu près 1h. Une séance similaire aura lieu Drupalcamp à Montréal le 24 octobre 2010 à 16h.
Cette page est gérée par Albert, qui vous invite à modifier cette page tant que vous le voulez!
Prérequis:
Connaître PHP
Compréhension du paradigme orienté objet un plus, mais pas nécessaire.
Parmi les sujets de discussion proposés :
- Test-driven development -- l'avantage d'utiliser Simpletest
- Comment ça marche -- Un test Simpletest, c'est l'équivalent de réinstaller Drupal et de faire un test, et non de faire un test sur une installation existante. Quelles sont les implications de cette façon de faire?
- L'anatomie d'un test simpletest: où réside-t-il, comment est-il structuré, comment est-il invoqué
- Nous écrirons un test ensemble et le testerons.
Simpletest avancé:
comment tester les envois de courriels par le système -- voir http://www.metaltoad.com/blog/simpletest-6x-gets-email-capture
système d'enregistrement de clics: http://drupal.org/project/simpletest_selenium (proposé par mathieu)
- différence entre Drupal 6 et 7
5. Introduction au fonctionnement de Simpletest
Simpletest a pour but de simuler l'utilisation qu'un être humain ferait d'une installation vierge du système; dans le but de tester certains cas d'utilisation. Différents cas d'utilisation peuvent partager un set up initial (création de comptes d'utilisateurs, de contenu fictif, etc.) Prenons l'exemple d'un module fictif qui doit afficher la chaîne de caractères t('Over a hundred active users') dès que le nombre d'utilisateurs franchit le cap des 100 utilisateurs qui ont au moins une entrée de blogue ayant 30 jours ou moins. Imaginez que vous n'utilisez pas Simpletest et que vous voulez prouver que ce module fonctionne correctement. Vous devez:
- Faire une nouvelle installation Drupal
- Y activer votre module et blog
- Créer un rôle qui peut créer des entrées de blogue
- Créer 100 utilisateurs
- Créer 100 entrées blogue, une pour chaque utilisateur.
- Vous assurer que la chaîne de caractère s'affiche dans le bloc pour un utilisateur anonyme.
- Changer la date d'une des entrées blogue pour que ça fasse plus de 30 jours.
- Vous assurer que la chaîne de caractère ne s'affiche pas dans le bloc pour un utilisateur anonyme.
Avec simpletest, vous allez simuler cette fonctionalité dans un document .test à l'intérieur de votre répertoire de module; vous trouverez en attachement un simple module à utiliser lors de cet atelier.
6. Questions
- Patrick
- Albert ou les autres, avez-vous déjà utilisé simpletest lors d'un projet/module?
- Albert
- Pour ma part j'ai utilisé Simpletest pour mettre en place de la fonctionalité (avec des patchs) sur des modules existants; ou pour "prouver" de façon formelle l'existance d'une erreur et/ou l'efficacité d'une solution sur des modules existants ou le core. Je n'ai jamais utilisé Simpletest pour le développement d'un nouveau module mais un module très simple sera développé avec Simpletest dans le cadre de cette formation.
- Patrick
- Y-a-t'il une intégration entre simpletest et drush pour rouler les tests en ligne de commande?
- Albert
Oui: drush test mail fait tous les tests et vous envoie les résultats par courriel à l'adresse du site. Voir aussi http://drupal.org/node/645286. Pour faire rouler les tests de façon plus spécifique, il est possible d'utiliser run-tests.sh.
- Patrick
- Est-ce possible de tester les formulaires GET/POST?
- Albert
- Oui, simpletest simule l'utilisation d'un site vierge par un être humain. Donc, si vous voulez faire un post et vous assurer que ça marche, vous pouvez utiliser le code suivant:
$this->drupalPost('node/add/story', array('title' => $this->randomName(32), 'body' => $this->randomName(64),), t('Save'));
- // le simulateur se trouve maintenant sur la page suivant ce post.
$this->assertText(t('created'));
- // si le mot 'created' n'apparaît pas sur la page suivante, c'est une erreur.
- Patrick
- Est-ce possible de tester les permissions de divers rôles/utilisateurs?
- Albert
- Oui -- pour chaque famille de tests faite avec Simpletest, vous devez créer un ou des utilisateurs fictifs avec des permissions. Le concept de rôle est traduit par une liste de permissions dans simpletest.
- Patrick
- Est-ce possible de précharger la base de données avec des données fictives pour les tests?
- Albert
- Pour chaque test dans chaque famille de tests, simpletest installe une toute nouvelle installation de Drupal. Pour chaque test, donc, il n'y a aucune donnée et aucun utilisateur. C'est à vous de les créer. Ainsi, pour créer des données fictives ou bien dans la famille de tests ou pour un test individuel, vous pouvez écrire par exemple:
for ($i = 0; $i < 50; $i++) {
- // simuler plusieurs fois de suite qu'on visite la page node/add/story, qu'on remplit les champts titre et body avec des données quelconques et qu'on appuie sur Save.
$this->drupalPost('node/add/story', array('title' => $this->randomName(32), 'body' => $this->randomName(64),), t('Save'));
Si jamais vous avez besoin de données réelles (i.e. dans certains cas la situation testée présume l'existance de données réelles et non de données fictive ou d'une installation verge), on peut utiliser simpletest_clone pour utiliser un clone de votre installation actuelle.
7. Référence
- API de simpletest: http://cwgordon.com/simpletest/doxygen/2008-june/main.html
8. Activation des modules
Simpletest for 6.x n'active pas automatiquement les dépendances pour les modules. Voir http://drupal.org/node/399642. Il faut donc les activer explicitement dans setUp(). Ce que je fais est de ne rien activer dans setUp(), mais plutôt le faire dans le corps du test, et d'installer la fonction suivante dans vos classes. À noter que l'utilisateur connecté au moment d'appeler cette fonction doit avoir la permission bonne permission:
$this->admin = $this->drupalCreateUser(array('administer site configuration'));
/** * Helper function to enable module(s). */ public function _enableModules($modules) { if(!is_array($modules)) { $modules = array($modules); } foreach($modules as $module) { $this->assertRaw($module); $this->drupalPost('admin/build/modules/list', array('status[' . $module . ']' => true), t('Save configuration')); if (strpos($this->drupalGetContent(), t('Some required modules must be enabled'))) { $this->drupalPost(NULL /* we're already at the right path, the Confirm page*/, array(), t('Continue')); } $this->drupalGet('admin/build/modules'); $raw = 'value="' . $module . '" checked="checked"'; $this->assertRaw($raw, t('Module @m has been activated because the raw html @r was found on the page.', array('@m' => $module, '@r' => $raw))); } } // pour D7 --- il faut que modules soit dans le format array(array(group => module, group => module))... public function _enableModules($modules) { foreach($modules as $group => $module) { $this->drupalPost('admin/modules', array('modules[' . $group . '][' . $module . '][enable]' => true), t('Save configuration')); if (strpos($this->drupalGetContent(), t('Some required modules must be enabled'))) { $this->drupalPost(NULL /* we're already at the right path, the Confirm page*/, array(), t('Continue')); } $this->drupalGet('admin/modules'); $raw = '"modules[' . $group . '][' . $module . '][enable]" value="1" checked="checked"'; $this->assertRaw($raw, t('Module @m has been activated because the raw html @r was found on the page.', array('@m' => $module, '@r' => $raw))); } }
9. Mode Verbose
- En activant le mode "verbose", vous pourrez voir l'état du testbot à un moment donné. Cependant si vous roulez un test plusieurs fois et le modifiez en cours de route, votre fureteur gardera en mémoire cache une ancienne version de la page, il faut donc rafraîchir votre aperçu si vous voyez quelque chose d'inattendu. Exemple: à un moment donné vous vous attendez à ce que votre testbot voit une page où c'est écrit "hello world", vous cliquez sur "verbose message" sur la page de résultats de test, ce qui vous ouvre une fenêtre avec ce que le testbot voit (une page Drupal). C'est cette page qu'il faut rafraîchir.
10. Roles
See also http://drupal.org/node/478520
protected function drupalCreateUserForRole($roles) { // Create a user assigned to that role. $edit = array(); $edit['name'] = $this->randomName(); $edit['mail'] = $edit['name'] . '@example.com'; $edit['roles'] = $roles; $edit['pass'] = user_password(); $edit['status'] = 1; $account = user_save('', $edit); $this->assertTrue(!empty($account->uid), t('User created with name %name and pass %pass', array('%name' => $edit['name'], '%pass' => $edit['pass'])), t('User login')); if (empty($account->uid)) { return FALSE; } // Add the raw password so that we can log in as this user. $account->pass_raw = $edit['pass']; return $account; } // et pour d7 // roles must be ids, for example, array(33 => 33, 2 => 2); // find these like this:, e.g. for role1 and role2 // // array(array_search('role1', user_roles()) => array_search('role1', user_roles()), array_search('role2', user_roles()) => array_search('role2', user_roles())) protected function drupalCreateUserForRole($roles) { // Create a user assigned to that role. $edit = array(); $edit['name'] = $this->randomName(); $edit['mail'] = $edit['name'] . '@example.com'; $edit['roles'] = $roles(); $edit['pass'] = user_password(); $edit['status'] = 1; $account = user_save(drupal_anonymous_user(), $edit); $this->assertTrue(!empty($account->uid), t('User created with name %name and pass %pass', array('%name' => $edit['name'], '%pass' => $edit['pass'])), t('User login')); if (empty($account->uid)) { return FALSE; } // Add the raw password so that we can log in as this user. $account->pass_raw = $edit['pass']; return $account; }