Comment les faux objets sont-ils couramment mal utilisés?


15

J'ai lu récemment un article qui disait que les faux objets étaient souvent mal compris et mal utilisés. Existe-t-il des anti-schémas moqueurs clairs que je peux rechercher?


est l'article que vous lisez celui-ci? martinfowler.com/articles/mocksArentStubs.html
keppla

non ... je ne me souviens pas de la source exacte, mais je posterai ici si je le fais
Armand

J'ai été amené à la tâche sur stackoverflow pour se moquer de l'API mongodb. J'ai été pointé vers un article de blog qui prétendait qu'il était faux de se moquer de toute classe que vous n'avez pas écrite. En fait, je ne suis pas d'accord avec cela, mais l'opinion est là-bas.
Kevin

Réponses:


13

Je déteste voir se moquer de simples cours de béton. Par exemple, prenez la classe simple suivante qui ne dépend d'aucune autre chose:

public class Person
{
    private readonly string _firstName;
    private readonly string _surname;

    public Person(string firstName, string surname)
    {
        if (String.IsNullOrEmpty(firstName))
        {
            throw new ArgumentException("Must have first name");
        }

        if (String.IsNullOrEmpty(surname))
        {
            throw new ArgumentException("Must have a surname");
        }

        _firstName = firstName;
        _surname = surname;
    }

    public string Name 
    {
        get
        {
            return _firstName + " " + _surname;
        }
    }
}

Dans tous les tests impliquant cette classe, je préfère de loin une vraie instanciée et utilisée plutôt qu'une interface comme «IPerson» qui soit retirée, une simulée utilisée et des attentes définies sur le. En utilisant le vrai, votre test est plus réaliste (vous avez les vérifications des paramètres en place et l'implémentation réelle de la propriété 'Nom'). Pour une classe simple comme celle-ci, vous ne rendez pas vos tests plus lents, moins déterministes ou brouillez la logique (vous n'aurez probablement pas besoin de savoir que Name a été appelé lors du test d'une autre classe) - qui sont les raisons habituelles de se moquer / tronçonnage.

Comme extension à cela, j'ai également vu des gens écrire des tests où la maquette est configurée avec une attente, puis la simulation est appelée directement dans le test. Sans surprise, le test réussira toujours ... hmmmm ...


Heureusement, les frameworks moqueurs que j'ai utilisés ont pu se moquer de classes concrètes, donc retirer les interfaces à des points gênants n'est pas un problème.
Armand

5
Cela ne change pas le problème - ce genre de chose simple ne devrait généralement pas être moqué même si vous utilisez quelque chose qui assouplit les contraintes techniques sur ce qui peut être moqué (par exemple, un cadre de simulation comme TypeMock ou un langage dynamique).
FinnNk

Ma règle d'or a toujours été de se moquer du comportement, pas des données.
ardave

10

Cela peut sembler évident, mais: n'utilisez pas d'objets fictifs dans le code de production! J'ai vu plus d'un exemple où le code de production dépendait des caractéristiques de certains objets MockHttpServletRequestfictifs ( du Springframework par exemple).


14
j'espère que vous avez suivi votre saint devoir et soumis le code à DailyWTF?
keppla

1
Dans mon travail précédent, il nous était expressément interdit de soumettre quoi que ce soit de notre base de code à DWTF.
quant_dev

9
@quant_dev: Le fait qu'ils aient une telle politique implique des choses effrayantes à propos de leurs développeurs ...
John Fisher

1
Pas vraiment. C'était une start-up qui devait développer rapidement une base de code pour vendre un produit, puis a commencé à le consolider et à le refactoriser pour rembourser la dette technique, à mesure que le produit arrivait à maturité et que le développement continu était entravé par le (manque de) conception initiale. Les gestionnaires savaient que l'ancienne base de code était de la merde et ont investi du temps et des ressources dans la refactorisation, mais ne voulaient pas risquer de publicité négative.
quant_dev

Prendre des raccourcis n'est pas vraiment suffisant pour vous procurer seulement tous les jours ...
poolie

9

À mon avis, c'est le contrôle excessif de l'invocation de la méthode sur les simulacres. Je pense que c'est une pratique appliquée par quelques frameworks de simulation comme EasyMock, où le comportement de simulation par défaut est d'échouer chaque fois qu'il y a une invocation de méthode supplémentaire qui n'était pas exactement spécifiée auparavant. Ce type de vérification de méthode fictive stricte peut conduire à des conceptions fragiles où la moindre modification du code peut entraîner l'échec de toute une série de tests, même si la fonctionnalité principale est toujours la même.

Une solution à cela commence à utiliser des talons au lieu de faux. Un article que j'ai trouvé particulièrement instructif sur le sujet a été trouvé dans Javadoc de Mockito: http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html (voir "2. Que diriez-vous d'un stubbing?" ), lien vers: http://monkeyisland.pl/2008/07/12/should-i-worry-about-the-unexpected/ .

J'ai apprécié de travailler avec Mockito jusqu'à présent, car il n'applique pas ce comportement de moquerie strict mais l'utilisation de stubs à la place. Il applique également la vérification des méthodes sur des spécificités au lieu de l'ensemble de l'objet factice; vous finissez donc par ne vérifier que les méthodes qui comptent vraiment dans votre scénario de test.

Il y a quelques livres ici et là je peux recommander de toucher ce sujet et moqueurs et général:

Modèles xUnit

L'art du test unitaire: avec des exemples dans .Net

Tests Java de prochaine génération: TestNG et concepts avancés (ce livre traite principalement de testNG mais il y a un beau chapitre sur la simulation)


+1 pour le point sur les vérifications excessives d'invocation de méthode. Cependant, il y a toujours le revers de la médaille où une invocation de méthode inattendue provoque un échec dans votre méthode. Heureusement, Mockito a le Answer.RETURNS_SMART_NULLSréglage pour les moqueries qui aide à diagnostiquer cela.
Bringer128

4

J'ai observé peu d'anti-modèles dans mon expérience.

  • Les classes de domaine sont moquées / tronquées lorsqu'un changement d'état peut se produire et cela doit être vérifié.
  • Tests d'intégration interagissant avec un mélange de classes factices et concrètes, ce qui va à l'encontre de l'objectif des tests d'intégration.
  • Utilisation involontaire de simulations dans le code de production (cela ne devrait jamais arriver)

Sinon, mon expérience avec les simulacres en particulier Mockito a été un jeu d'enfant. Ils ont rendu les tests très faciles à écrire et à maintenir. Le test d'interaction vue / présentateur GWT est beaucoup plus facile avec les simulations que le GWTTestCase.


2 & 3 sont des problèmes précis! Avez-vous un exemple simple de (1)?
Armand

2

Je trouve que les tests qui utilisent des simulations sur plusieurs couches d'une application sont particulièrement difficiles à déchiffrer et à modifier. Cependant, je pense que cela a été atténué ces dernières années par l'amélioration des API du cadre de simulation (j'utilise JMock lorsque cela est pratique).

Il y a 5 ou 6 ans, des API comme EasyMock étaient puissantes mais très lourdes. Souvent, le code de test qui l'utilisait était des ordres de grandeur plus compliqué que le code qu'il testait. À l'époque, j'essayais d'influencer les équipes dans lesquelles j'étais pour l'utiliser avec parcimonie et me contenter de simulations artisanales simples qui étaient simplement des implémentations alternatives d'interfaces spécifiquement destinées aux tests.

Récemment, mes opinions bien arrêtées sont devenues plus souples, car les API moqueuses ont rendu les tests qui les utilisent plus lisibles. Essentiellement, je veux que mon code (y compris les tests) soit modifiable par d'autres développeurs sans leur donner l'impression de passer au crible un bourbier d'appels d'API obscurs.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.