mercredi 15 juin 2011

Mock et Stub, la différence !

Mock et Stub, 2 patterns très pratique pour les tests unitaires, mais savez vous ce qui les différencie ?

Le Mock et le Stub sont tous les deux des objets qui permettent de simuler le comportement d'un autre objet. On les appelle très souvent des fake objects.

L'utilité, est de pouvoir tester un comportement dans un test unitaire en évitant :
 - d'appeler une classe que vous ne voulez pas spécialement tester (son fonctionnement fait déjà l'objet de tests unitaires)
 - d'appeler une classe qui nécessite des éléments externes non disponibles au moment des tests (BDD, Webservice ...)
 - d'appeler une classe qui générera une action "non voulu" (Envoi de mail, Alerte).

En fait, ce qui différencie ces 2 objets, c'est la manière d'effectuer le test.

Le Stub possédera des méthodes, qui vous permettront de tester l'état de l'objet après utilisation.

Exemple en php (phpunit) :


class MailerStub extends Mailer {
    private $_nb = 0;
    public function send () {
         $this->_nb++;
    }

    public function getCount () {
        return $this->_nb;
    }
}

class MyStubTest extends PHPUnit_Framework_TestCase {
      public function testLogEmail () {
          $mailer = new MailerStub ();
          $logger = new Logger ('email', array ('emailer'=>$mailer));
          $logger->log('test');
          $this->assertEquals ($mailer->getCount (), 1);
      }
}

Le Mock vous permettra de tester le comportement de l'objet, et de savoir par exemple, si telle ou telle méthode a bien été appelé (avec les bons paramètres)

Exemple en php (phpunit) :

class MyMockTest extends PHPUnit_Framework_TestCase {
    public function testLogEmail () {
        $mockmailer = $this->getMock('Mailer');
         // On veut que la méthode send soit appelé une seule et unique fois
        $mockmailer->expects($this->once())->method('send');

        $logger = new Logger ('email', array ('emailer'=>$mockmailer));
        $logger->log('test');

    }
}

En résumé, avec le Stub, nous testons l'état final de notre "faux" objet, sans se soucier de la manière ou nous arrivons à cet état. Avec le Mock, nous testons la manière d'arriver dans cet état.

Dernière petite subtilité qu'il faut comprendre, le Mock communique directement avec votre SUT (System Under Test), il va lui même générer les Failures alors que dans le cas du Stub, c'est votre SUT qui va tester si l'état final du Stub est correct.

Pour aller plus loin, je vous conseille de lire un article (la référence) de Martin Fowler, Mocks aren't Stubs
A voir également un exemple d'utilisation du Mock pour tester les Erreurs, Warnings et Notices en php 

Aucun commentaire: