Créer un mock en PHP pour Atoum – partie 1

Créer un mock en PHP pour Atoum - partie 1

Voyons cette semaine, et la prochaine, comment  créer un mock pour tester unitairement des classes PHP avec Atoum.

Atoum ?

A vos souhaits. Voilà, maintenant que c’est fait, passons aux choses sérieuses.

Atoum est un framework qui permet de tester unitairement des classes écrites en PHP.

Mais si vous savez, le truc qu’on est censé faire pendant le développement, réutilisable à chaque modification pour éviter les régressions et tester les modifications.

Un mock ?

Un mock, qui peut être traduit par bouchon, est une classe ou un objet qui remplace une classe ou un objet existant et simule son comportement.

L’intérêt est simple : créer un objet ou une classe pré configuré avec des propriétés et des méthodes modifiées utiles au test, pour éviter par exemple une connexion à une base de données ou à un Web service.

Il existe plusieurs types de mock : le mock d’un objet déjà instancié, traité dans cet article, et celui du mock d’une classe, que nous verrons dans le prochain.

Mock d’un objet déjà instancié

La documentation décrit très bien un type de mock : celui qui consiste à passer un objet déjà instancié, dont le comportement à été modifié, à la classe à tester.

La classe à tester

D’ailleurs, il est parfois nécessaire de changer légèrement l’implémentation de la classe à tester pour l’adapter aux tests.

Avec cette classe :

class User {
	private $userDb;

	public function __construct($id) {
		$this->userDb = new \Database\DatabaseTable("users", $id);
	}

	public function getUserData() {
		return $userDb->query();
	}

	public function getAge() {
		$data = $this->getUserData();
		return date("Y") - $data["birthYear"];
	}
}

Il est (presque) nécessaire d’écrire le constructeur autrement :

public function __construct($id, $userDb = null) {
	if ($userDb === null)
		$this->userDb = new \Database\DatabaseTable("users", $id);
	else
		$this->userDb = $userDb;
}

Vous pouvez aussi ajouter un setter pour définir userDb.

Le test

Dans le test, pour instancier le mock, il suffit de le faire en préfixant son namespace avec \mock :

$mockDb = new \mock\Database\DatabaseTable();

Automatiquement, vous avez accès à un objet qui hérite directement de la classe d’origine, et dont vous pouvez modifier le comportement à votre guise.

Pour changer le comportement de query :

$mockDb->getMockController()->query = array("firstName" => "Maurice", "lastName" => "Moss", "birthYear" = 1973);

Ici, à chaque appel, query renverra un tableau identique. Vous pouvez également définir une fonction ou indiquer un jeu de données différents selon un compteur d’appels.

Et pour l’utiliser dans un test :

public function testUserAge() {
	$mockDb = new \mock\Database\DatabaseTable();
	$mockDb->getMockController()->query = array("firstName" => "Maurice", "lastName" => "Moss", "birthYear" = 1973);

	$this
		->given($u = new User(5, $mockDb))
		->integer($u->getAge())
		->isEqualTo(42);
}

Le mot de la fin

Souvent les classes instancient elles-mêmes des objets, un gestionnaire d’utilisateurs par exemple instancie plusieurs objets utilisateurs.

Et dans ce cas, il n’est pas possible de passer les objets déjà instanciés à la classe, pour vérifier… qu’elle les instancie bien.

C’est le principe du mock que nous verrons la semaine prochaine.

L'illustration de cet article est une image sous licence CC BY 2.0 par SuSanA Secretariat

Cet article vous a été utile ? Partage it !

3 réflexions au sujet de « Créer un mock en PHP pour Atoum – partie 1 »

  1. Protip : $mockDb->getMockController()->query = array(« firstName » => « Maurice », « lastName » => « Moss », « birthYear » = 1973) peut être reformuler en $this->calling($mockDb)->query = array(« firstName » => « Maurice », « lastName » => « Moss », « birthYear » = 1973).
    Il est également possible de d’affecter une fonction anonyme pour définir un comportement en fonction des arguments reçus par la méthode « mockée ».

    1. Bonjour mageekguy,

      D’abord, bravo, et merci pour ce framework, il est vraiment sympa à utiliser 🙂

      En fait, je trouvais la notation avec getMockController() plus clair (pour moi). Quel est l’avantage de la méthode calling() ?

      David

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Si vous le souhaitez, renseignez le champ 'Nom' de cette façon : 'VotreNom@VotreMotClef' pour obtenir une ancre optimisée pour les moteurs de recherche.