Zend_Test_PHPUnit_DbCouper l'accès aux données au modèle métier requiert souvent l'utilisation d'une base de données pour les tests. Mais la base est persistente entre les tests, et leur isolation est donc rompue, de plus, configurer une base de données pour des tests peut vite s'avérer complexe. L'extension sur les bases de données de PHPUnit simplifie les procédures de tests en offrant des mécanismes de preconditions et postconditions sur la base entre les tests. Ce composant étend donc l'extension base de données de PHPUnit en ajoutant du code spécifique à Zend Framework. Les tests de base de données peuvent être résumés en 2 notions : DataSets et DataTables. En interne, PHPUnit peut créer un objet dont la structure est callée sur une base de données dont les tables et les enregistrements sont montés depuis un fichier de configuration ou un contenu réel. Cet objet abstrait peut alors être comparé à des structures. Un cas courant en tests de base de données consiste à configurer des tables en les remplissant de données fictives, éxecuter du code "utile", puis comparer la base de données avec une structure. Zend_Test_PHPUnit_Db simplifie cette tâche en offrant la possibilité de créer des DataSets et des DataTables provenant d'instances de Zend_Db_Table_Abstract ou Zend_Db_Table_Rowset_Abstract. Aussi, ce composant permet l'utilisation de n'importe quel Zend_Db_Adapter_Abstract alors qu'à l'originine PHPUnit ne fonctionne qu'avec PDO. Un adaptateur de test basé sur Zend_Db_Adapter_Abstract est aussi inclus. Il permet d'instancier un adaptateur qui ne requiert aucune base de données réelle. QuickstartConfigurer un cas de tests DatabaseNous allons à présent écrire des tests pour la base de données Bug de la documentation sur Zend_Db_Table. D'abord, nous testons qu'insérer un nouveau bug est bien sauvegardé en base. Nous devons créer un cas de tests sous forme de classe étendant Zend_Test_PHPUnit_DatabaseTestCase. Cette classe étend elle- même PHPUnit Database Extension, qui étend alors PHPUnit_Framework_TestCase. Un cas de test pour base de données contient deux méthodes abstraites à définir, une concernant la connexion à la base et l'autre concernant les données à utiliser comme source pour les tests.
Ici, nous créons la connexion à la base et nous y injectons des données fictives de test. Les éléments suivants sont importants à noter :
Spécifier un jeu de données (DataSet)Dans l'exemple précédent, nous avons préciser un fichier de jeu de données. Nous allons maintenant le créer, au format XML :
Nous allons travailler sur ces quatre entrées dans la table "zfbugs" après. Le script MySQL suivant est nécessaire pour l'exemple:
Quelques tests initiauxMaintenant que nous avons écrits les deux méthodes obligatoires pour Zend_Test_PHPUnit_DatabaseTestCase et que nous avons préciser avec quoi remplir la base et ses tables, nous pouvons commencer à écrire des tests afin d'effectuer des assertions. Voyons un test pour l'insertion d'un nouveau bug
Au dessus de la ligne $bugsTable->insert($data);, tout devrait vous être familier. La ligne d'après contient le nom de la méthode d'assertion. Nous souhaitons vérifier qu'après l'insertion d'un bug, la base a été correctement mise à jour avec les données. Ainsi, nous utilisons un objet de requête de jeu de données, instance de Zend_Test_PHPUnit_Db_DataSet_QueryDataSet et nous lui fournissons notre connexion à la base de données. Puis nous indiquons à notre objet de requête qu'il contient une table "zfbugs" contenant les données d'une requête SQL statement. Cet état actuel est alors comparé à un état contenu dans un fichier XML "bugsInsertIntoAssertions.xml". Ce fichier XML est le même que celui des données d'origine, à l'exception qu'il contient lui les données supplémentaires attendues:
Il existe d'autres manière de vérifier que l'état actuel de la base est équivalent à un état attendu. La table "Bugs" de l'exemple connait déja sont état interne, utilisons ceci à notre avantage. L'exemple suivant teste que la suppression de données dans la table est possible:
Ici nous créons un objet représentant un jeu de données pour une table, instance de Zend_Test_PHPUnit_Db_DataSet_DbTableDataSet. Il prend en paramètre un objet Zend_Db_Table_Abstract et l'ajoute au jeu de données avec le nom de la table, dans notre exemple : "zfbugs". Vous pourriez ajouter plus de données dans le jeu de données en utilisant addTable() plusieurs fois. Ici nous ne possédons qu'une seule table et nous la comparons à un état défini dans "bugsDeleteAssertion.xml" qui est en fait le jeu de données original moins la données supprimée : celle ayant l'id 4. Voyons maintenant comment vérifier que deux tables soient identiques (et non deux jeux de données correspondants à de telles tables). Ajoutons un test à notre scénario qui va vérifier la mise à jour de données.
Ici, nous récupérons l'état de la table depuis un objet Zend_Db_Table_Rowset_Abstract au moyen de Zend_Test_PHPUnit_Db_DataSet_DbRowset($rowset) qui crée une représentation de l'état interne des données du rowset. Nous comparons enfin cet état grâce à l'assertion $this->assertTablesEqual() Utilisation, API et possibilités d'extensionLe Quickstart permet déja de se rendre compte des capacités de tests d'une base de données avec PHPUnit et Zend Framework. Cette section donne un aperçu de l'API de Zend_Test_PHPUnit_Db ainsi que de son fonctionnement interne.
La classe Zend_Test_PHPUnit_DatabaseTestCaseLa classe Zend_Test_PHPUnit_DatabaseTestCase étend PHPUnit_Extensions_Database_TestCase, celle-ci permet de configurer un jeu de données concernant la base, pour chaque test. L'implementation du Zend Framework offre quelques fonctionalités supplémentaires par rapport à l'extension PHPUnit concernant les bases de données, ceci dans le but d'utiliser des ressources provenant de Zend_Db. Voici le scénario classique d'un test de base de données :
La classe Zend_Test_PHPUnit_DatabaseTestCase permet les tests de base de données à l'echelle du Zend Framework. Le tableau suivant liste uniquement les nouvelles méthodes par rapport à la classe PHPUnit_Extensions_Database_TestCase, dont l'» API est documentée dans la documentation de PHPUnit.
Intégrer les tests de bases de données avec les tests de contrôleursPHP n'autorise pas l'héritage multiple, donc vous ne pouvez utiliser les tests de contrôleurs et de bases de données en même temps via héritage. Cependant, vous pouvez utiliser Zend_Test_PHPUnit_Db_SimpleTester dans vos tests de contrôleurs pour configurer un environnement relatif à la base pour chaque test de contrôleur. Example #1 Exemple d'intégration d'une base de données Cet exemple reprend le test de UserController utilisé dans la documentation de Zend_Test_PHPUnit_ControllerTestCase et y inclut la gestion d'une base de données.
Ici le jeu de données XML "initialUserFixture.xml" est utilisé pour monter des données en base avant chaque test, exactement de la même manière que DatabaseTestCase le fait en interne. Utiliser l'adaptateur de testsIl peut être nécessaire quelques fois de vouloir tester l'application, mais sans base de données réelle physique. Zend_Test_DbAdapter offre des possibilités d'utiliser une implémentation de Zend_Db_Adapter_Abstract sans avoir à ouvrir une connexion vers une base physique. En plus, cet adaptateur est très facilement déguisable car aucun paramètre de constructeur n'est nécessaire. L'adaptateur de tests agit comme une pile pour des résultats de base. L'ordre des résultats doit être implémenté manuellement ce qui peut devenir assez complexe, mais cet adaptateur est très pratique dans le cas où un ensemble logique de requêtes est éxecuté et que vous connaissez l'ordre précis dans lequel les résultats doivent être retournés.
Le comportement des adaptateurs réels est simulé afin que des méthodes telles que fetchAll(), fetchObject(), fetchColumn() puissent fonctionner avec l'adaptateur de tests. Bien sûr, INSERT, UPDATE et DELETE peuvent être empilés aussi, mais vous ne pourrez alors tester que $stmt->rowCount() car ces types de requêtes ne retournent pas de résultats. Par défaut, le profiler est activé pour que vous puissiez récupérer la requête éxecutée de manière textuelle, avec ses paramètres donc.
L'adaptateur de test ne vérifie jamais si la requête spécifiée est réellement de type SELECT, DELETE, INSERT ou UPDATE. L'ordre exact de retour des données doit être spécifié manuellement dans l'adaptateur de tests. L'adaptateur de tests définit aussi les méthodes listTables(), describeTables() et lastInsertId(). De plus en utilisant setQuoteIdentifierSymbol() vous pouvez spécifier quel symbole utilisé pour l'échappement, par défaut aucun n'est utilisé.
|