2010-06-22 17 views
1

Supposons que j'ai une interface avec beaucoup de méthodes que je veux me moquer pour un test, et supposons que je n'ai pas besoin de faire quoi que ce soit, j'ai juste besoin de l'objet sous test pour en avoir une instance. Par exemple, je souhaite exécuter des tests de performances/benchmarks sur un certain code et ne pas souhaiter que les méthodes de cette interface contribuent.façon pas cher de se moquer d'une interface sans surcharge d'exécution

Il y a beaucoup d'outils pour le faire facilement, par exemple

Interface mock = Mockito.mock(Interface.class); 
ObjectUnderTest obj = ... 
obj.setItem(mock); 

ou autre chose.

Cependant, ils viennent tous avec certains frais généraux d'exécution que je préfère éviter:

  • Mockito enregistre tous les appels, stashing les arguments pour vérification ultérieure
  • JMock et d'autres (je crois) vous obliger à définir ce qu'ils vont faire (pas si grave), et ensuite l'exécution passe par un proxy de différentes sortes pour appeler la méthode.
  • Bon vieux java.lang.reflect.Proxy et les amis passent tous au moins quelques appels de méthode sur la pile avant d'arriver à la méthode à invoquer, souvent de manière réfléchie.

(je suis prêt à corriger sur l'un des détails de ces exemples, mais je crois que le principe est.)

Ce que je vise est un non-op « véritable » mise en œuvre de l'interface, comme je pourrais écrire à la main avec tout retournant null, false ou 0. Mais cela n'aide pas si je me sens paresseux et l'interface a beaucoup de méthodes. Alors, comment puis-je générer et instancier une telle implémentation sans opération d'une interface arbitraire à l'exécution?

Il existe des outils tels que Powermock, CGLib qui utilisent la génération de bytecode, mais seulement dans le cadre plus large du moqueur/proxy et je n'ai pas encore trouvé ce qu'il faut choisir parmi les internes. OK, donc l'exemple peut être un peu artificiel et je doute que le proxy ait un impact trop important sur les timings, mais je suis curieux de savoir comment générer une telle classe. Est-ce facile dans CGLib, ASM?


EDIT: Oui, cela est l'optimisation prématurée et il n'y a pas vraiment besoin de le faire. Après avoir écrit cette question, je pense que la dernière phrase ne m'a pas vraiment fait comprendre que je m'intéressais plus à la façon de le faire en principe, et aux moyens faciles de créer une classe dynamique que le cas concret que j'ai donné. Peut-être mal formulé depuis le début.

Répondre

3

Vous ne savez pas si c'est ce que vous cherchez, mais l'assistant "nouvelle classe" dans Eclipse vous permet de créer une nouvelle classe et de spécifier la superclasse et/ou l'interface (s). Si vous le laissez, il code automatiquement les implémentations factices de toutes les méthodes d'interface/abstrait (renvoyant null sauf si void). C'est assez facile à faire. Je pense que les autres IDE "big name", tels que NetBeans et Idea, ont des fonctionnalités similaires.


EDIT:

En regardant votre question, je me demande pourquoi vous seriez préoccupé par la performance de procurations auto lorsqu'ils traitent avec des classes de test. Il me semble que si la performance est un problème, vous devriez tester la fonctionnalité "réelle", et si vous avez affaire à des classes pour la plupart non implémentées, vous ne devriez pas être dans une situation de test où les performances sont importantes.

+1

+1 pour l'édition –

+2

D'accord. Cela sent aussi l'optimisation prématurée, combien de picosecondes sont ces deux couches de pile supplémentaires qui vous coûtent avec les proxies dynamiques de Java, de toute façon? –

+0

Oui, je sais. En toute honnêteté, la partie «comment on peut le faire» est plus importante que «j'ai vraiment besoin de le faire». –

0

Il faudrait un peu de travail pour construire l'utilitaire, mais probablement pas trop difficile pour l'interface Java de base sans "bordures" (annotations, etc), pour utiliser la génération de code Javassist pour créer textuellement une classe à l'exécution. versions nulles de toutes les méthodes définies sur l'interface. Cela serait différent des objets proxy Javassist ProxyFactory (ou CGLib Enhancer) qui auraient encore quelques couches d'indirection. I pense il n'y aurait pas de surcharge dans la classe résultant du mode de génération de bytecode direct. Si vous êtes courageux, vous pouvez également plonger dans l'ASM pour faire la même chose.