Mocker

Dans une optique de mise en place d’une plateforme d’intégration je suis amené à travailler sur les tests unitaires et plus particulièrement des Mocks. Cet article me servira de synthèse sur le principe du mocking. N’hésitez pas à apporter votre expérience sur le sujet et à compléter (ou corriger) mes dires.

Qu’est-ce que le mocking ?

Par définition, un test unitaire ne doit pas toucher au système de fichiers, à la base de données, etc. Un mock permet de simuler une classe et ses méthodes. Un mock est créé à partir de l’interface d’une classe et les valeurs de retours de chacun de ses attributs peuvent être paramétrées.
Un mock au sein d’une méthode de test permet de se concentrer uniquement sur la méthode à tester. Au premier aspect, on peut considérer que du coup le comportement de la classe sera différent lors du test (par exemple : Si on réalise le mock d’une classe uploadant un fichier, on ne réalise pas vraiment cet upload.) mais en réalité la classe dont on réalise un mock est censée avoir déjà été testée. Du coup, nos tests restent cohérents.

Différents frameworks de Mocks

RhinoMock : Apprécié, beaucoup utilisé mais peu maintenu. Apparemment pas encore de support officiel du framework 4.0

Moq : Plutôt récent, conçu pour pouvoir profiter des avantages du framework 3.5. Il tire notamment avantage des expressions lambdas. De cette manière la syntaxe reste très logique, facile à aborder et permet de profiter de l’IntelliSense.

NMock2 : Bien documenté et à jour. Très transparent mais la syntaxe est quant à elle assez verbeuse et ne permet pas l’utilisation de l’IntelliSense (un plugin pour ReSharper existe pour l’ajouter). Je trouve son utilisation moins intuitive que Moq.

Dans la suite de cet article nous allons nous intéresser aux syntaxes de Moq et de NMock2 pour générer des mocks basiques.

Comparaison Moq et NMock2

Prenons une classe basique avec une seule méthode prenant un string en paramètre et retournant un autre string :

public class MaClasse {
public string MaMethode(string maString)
{
if (maString == « ping ») return « pong »;
return « out »;
}
}

Pour utiliser Moq nous pouvons créer une interface publique de cette classe :

public Interface IMaClasse
{
string MaMethode(string maString);
}

Ou bien mettre notre classe en public et utiliser le mot clef virtual dans nos méthodes.

Nous pouvons ensuite créer notre mock :
var mock = new Mock<IMaClasse>(); //A partir de notre interface
ou
var mock = new Mock<MaClasse>(); //A partir de notre classe
Puis initialiser les valeurs que retournera notre méthode en fonction des paramètres :
mock.Setup(foo => foo.MaMethode(« ping »)).Returns(« pong »);

Ou bien, pour n’importe quelle chaîne :
mock.Setup(foo => foo.MaMethode(It.IsAny<string>())).Returns(« out »);

La classe statique It permet aussi de spécifier des Regex, intéressant dans le cas de méthodes qui doivent retourner un résultat particulier en fonction d’une valeur entrée (requête, fichier à enregistrer en fonction de leur extension, …).

Nous avons donc paramétré une valeur de retour en fonction d’un paramètre d’entré. Il nous suffit maintenant de simuler l’appel à cette méthode :
mock.Object.MaMethode(ParametreInitialiséPrécédemment);
Par exemple : String toto = mock.Object.MaMethode(« ping »);
toto égalera “pong”.

Avec NMock2, nous devons mettre nos méthodes en virtual. Le mock étant du type de l’objet à mocker nous n’utilisons pas d’interface.
On commence par créer un objet de type Mockery, qui sera en quelque sorte notre fabrique de mock :
var mockery = new Mockery();
Ensuite on crée le mock de notre classe :
var maClasseMockee = mockery.NewMock<MaClasse>();
On peut maintenant paramétrer les comportements avec la classe Expect :
Expect.Once.On(maClasseMockee).Method(« MaMethode »).With(« ping »).Will(Return.Value(« pong »));
Expect.Once.On(maClasseMockee).Method(« MaMethode »).WithAnyArguments().Will(Return.Value(« out »));
Ce lien délivre une explication très détaillée avec un schéma de l’arborescence de cette classe : http://sourceforge.net/apps/mediawiki/nmock2/index.php?title=Expectations.

En résumé, comme avec Moq, on paramètre la valeur de retour (Will(Return.Value(laValeur))) lors de l’appel d’une méthode (Method(“MaMethode”)) sur notre mock (On(maClasseMockee)) avec un paramètre spécifique (With(“ping”) ou WithAnyArguments() pour n’importe quel argument).

Et nous récupérons cette valeur en appelant notre méthode de manière transparente :
maClasseMockee.MaMethode(« ping ») retournera “pong”
maClasseMockee.MaMethode(« poc ») retournera “out”

Conclusion

A l’usage, l’utilisation de Moq a une syntaxe plus facile à aborder et plus logique.
NMock2 a par contre une utilisation plus transparente avec un mock du même type que l’objet souhaité et permet ainsi un appel classique aux méthodes. Mais sa mise en place reste lourde et moins intuitive.

Par JCVASSELON

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s