2010-05-05 4 views
17

J'ai une classe qui a une méthode interne et je veux me moquer de la méthode interne. Mais je suis incapable de me moquer d'elle, c'est-à-dire qu'elle n'appelle pas la fonction simulée mais appelle la fonction d'origine. Y'a-t-il une quelconque façon de réussir cela ?Comment se moquer de la méthode interne d'une classe?

Edit: En fait, je suis un novice du Moq. J'ai beaucoup de classes et de méthodes de classes à tester en utilisant le Moq. De nombreuses classes sont internes, beaucoup ont des méthodes internes, beaucoup ont des méthodes non-virtuelles. Et ne peut pas changer la signature sur les méthodes et les classes. Quelqu'un peut-il s'il vous plaît laissez-moi savoir comment tester ce scénario en utilisant Moq. Ou alors, n'hésitez pas à me suggérer un autre cadre de test facile à apprendre et à utiliser. Pourquoi voudriez-vous simuler une méthode interne?

Répondre

2

Si vous trouvez le besoin de simuler une méthode interne, disons de contourner une dépendance ou une interaction, vous devriez peut-être envisager une nouvelle conception de la classe.

Inversion of Control et Dependency Injection sont quelques stratégies de conception possibles qui peuvent réduire le couplage et augmenter la cohésion de vos classes et éliminer le besoin de se moquer des méthodes internes.

Je ne crois pas qu'il y ait un chemin clair vers le moq non-public. Mais, si vous devez absolument, vous pouvez utiliser TypeMock Isolator pour simuler à peu près n'importe quoi.

Aussi, juste pour ne pas se perdre dans le din: Thomas a lié un bon article sur l'utilisation des MS Moles libres pour se moquer des membres non-publics.

Mocking the Unmockable: Using Microsoft Moles with Gallio

+1

En effet, en se moquant des méthodes privées est typique odeur de code. – mikek

+5

Je ne suis pas du tout d'accord: si vous faites TDD, alors moquer des trucs internes est une chose ordinaire, tous les jours ... –

+0

@Thomas - Je comprends votre point de vue. Mais vous devez comprendre que la stratégie classique est définie comme le test d'un comportement de classes, généralement par interface, plutôt que par implémentation interne car cela couple étroitement vos tests à l'implémentation interne et induit inertie et casse lors de la refactorisation. Je dois dire que vous êtes en minorité avec votre opinion. note: j'ai lu un peu de votre blog et je sais que vous êtes très attentionné et que TDD vous est cher - je ne suis tout simplement pas d'accord avec votre désaccord. ;-) –

1

Les tests unitaires devraient tester l'interface d'une classe. Vous pouvez simuler les dépendances, mais les détails d'implémentation de la classe elle-même (comme les méthodes privées) doivent être testés dans le cadre de la classe entière, pas séparément, et non modifiés pour le test (sinon vous testeriez une unité différente être utilisé).

Si vous pensez qu'il est nécessaire de changer la méthode pour rendre la classe testable, refactorisez la classe afin que la partie difficile devienne une dépendance, ou autrement substituable par paramètre ou sous-classe.

+0

Et si vous développez votre test de code, d'abord en baby-step? Vous aurez régulièrement besoin de traiter avec le code interne d'une façon ou l'autre ... –

3

Pas avec Moq.

Mais vous pouvez utiliser le framework gratuit Moles de MS pour faire de telles choses. J'ai écrit à ce sujet ici: Mocking the Unmockable: Using Microsoft Moles with Gallio. (ça s'applique non seulement à Gallio, mais ça donne une bonne impression globale de ce que l'on peut faire avec les Moles ...). L'autre alternative serait Typemock ...

HTH. Thomas

+0

+ pour la rédaction sur les outils gratuits –

+1

Wrong (au moins en 2016). Voir la réponse de Daryn. – mhvelplund

+0

À partir de 2016, MS Moles a été remplacé par MS Fakes, selon http://wayback.archive.org/web/20160316031214/http://research.microsoft.com/en-us/projects/moles/. – clacke

0

Si vous avez besoin de tester beaucoup de code que vous ne pouvez pas changer, vous devriez aller avec MS Moles ou TypeMock depuis le début.

Les frameworks de moqueurs gratuits comme Moq ne vous offrent que du support sur les interfaces et les méthodes virtuelles. Cela ne semble pas comme si vous irez loin avec ça ...

Thomas

55

Vous pouvez facilement simulacres des méthodes virtuelles internes en ajoutant ce qui suit à votre AssemblyInfo.cs:

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] // namespace in Moq 
[assembly: InternalsVisibleTo("YourTestClass")] 

Si votre ensemble est fortement nommé, vous aurez besoin d'inclure la clé publique pour DynamicProxyGenAssembly2 (Merci à commenter par @bvgheluwe; source: Moq quickstart guide):

[assembly:InternalsVisibleTo("DynamicProxyGenAssembly2,PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] 

Je ne comprends pas pourquoi la réponse acceptée dit que vous ne devriez jamais le faire. N'est-ce pas ce que vous faites lorsque vous utilisez la technique d'injection de dépendance «Extraire et remplacer» (méthode d'usine locale) décrite par Roy Osherove au Chapter 3 of The Art Of Unit Testing?

+1

Ça m'a beaucoup aidé. Je vous remercie! – Fabian

+9

Ceci devrait être la réponse acceptée. C'est un tout autre débat de savoir si se moquer d'une méthode interne est la bonne chose à faire, mais si vous avez décidé que c'est ce que vous voulez faire, c'est la façon de le réaliser. – CraigTP

+2

Cela ne va pas fonctionner. Vous avez également besoin d'une clé publique. – max

22

Marquer la méthode comme internal *protected* (aussi virtuel bien sûr)

+2

omg, vous l'avez résolu. – max

+0

Cela fonctionne, mais pouvez-vous nous dire pourquoi cela fonctionne? – MrLore

+1

@MrLore cela fonctionne parce que "_protected_ internal" signifie que la méthode peut être accédée par une sous-classe dans _any_ assembly, et si vous la marquez "virtuelle" alors votre sous-classe peut fournir une implémentation personnalisée – andreister

Questions connexes