2008-09-30 9 views
34

Je suis novice en matière de simulation d'objets, mais je comprends que mes classes doivent implémenter des interfaces afin de se moquer d'elles. Le problème que j'ai est que dans ma couche d'accès aux données, je veux avoir des méthodes statiques, mais je ne peux pas mettre une méthode statique dans une interface.Comment se moquer des méthodes statiques?

Quel est le meilleur moyen de contourner ce problème? Devrais-je simplement utiliser des méthodes d'instance (ce qui me semble faux) ou existe-t-il une autre solution?

Répondre

22

Je voudrais utiliser un modèle d'objet de méthode. Avoir une instance statique de ceci, et l'appeler dans la méthode statique. Il devrait être possible de sous-classer pour le test, en fonction de votre cadre moqueur.

-à-dire dans votre classe avec la méthode statique ont:

private static final MethodObject methodObject = new MethodObject(); 

public static void doSomething(){ 
    methodObject.doSomething(); 
} 

et votre objet méthode peut être très simple, facilement testé:

public class MethodObject { 
    public void doSomething() { 
     // do your thang 
    } 
} 
+0

Avez-vous de bonnes références pour ce modèle? Je ne suis pas sûr de savoir comment j'y arriverais. – brien

+0

Err, pas réellement. Je ne suis pas sûr si j'ai fait ce nom, ou il est considéré plus comme un idiome que comme un modèle, mais je ne vois pas de références décentes par Google. Continuera à regarder bien. – Grundlefleck

+1

Merci, l'exemple m'a aidé à comprendre ce que vous vouliez dire. – brien

23

Oui, vous utilisez des méthodes d'instance . Les méthodes statiques disent essentiellement: "Il y a une façon d'accomplir cette fonctionnalité - ce n'est pas polymorphe." Le moqueur repose sur le polymorphisme. Maintenant, si vos méthodes statiques ne se soucient pas de l'implémentation que vous utilisez, elles pourraient être en mesure de prendre les interfaces comme paramètres, ou peut-être travailler sans interagir avec l'état - mais sinon vous devriez utiliser instances (et probablement l'injection de dépendance pour câbler tout ensemble).

4

Utilisez des méthodes d'instance lorsque cela est possible.

Utilisez public Func [T, U] (références de fonctions statiques qui peuvent être substituées à des fonctions fictives) où les méthodes d'instance ne sont pas possibles.

5

Vous essayez peut-être de tester un point de départ trop profond. Un test n'a pas besoin d'être créé pour tester chaque méthode individuellement; Les méthodes privées et statiques doivent être testées en appelant les méthodes publiques qui appellent ensuite les méthodes privées et statiques à tour de rôle.

Disons donc que votre code est comme ceci:

public object GetData() 
{ 
object obj1 = GetDataFromWherever(); 
object obj2 = TransformData(obj1); 
return obj2; 
} 
private static object TransformData(object obj) 
{ 
//Do whatever 
} 

Vous n'avez pas besoin d'écrire un test contre la méthode TransformData (et vous ne pouvez pas). Au lieu de cela, écrivez un test pour la méthode GetData qui teste le travail effectué dans TransformData.

25

J'ai trouvé un blog via google avec quelques grands exemples sur la façon de le faire:

  1. classe Refactoriser être une classe d'instance et implémenter une interface.

    Vous avez déjà déclaré que vous ne voulez pas faire cela.

  2. Utilisez une classe d'instance wrapper avec les délégués pour les classes statiques membres

    cette façon, vous pouvez simuler une interface statique par les délégués.

  3. Utilisez une classe d'instance emballage avec les membres protégés qui appellent la classe statique

    Ceci est probablement le plus facile à se moquer/gérer sans refactoring car il peut juste être héritée de et étendu.

1

Une solution simple est de permettre de changer la mise en œuvre de la classe statique via un setter:

class ClassWithStatics { 

    private IClassWithStaticsImpl implementation = new DefaultClassWithStaticsImpl(); 

    // Should only be invoked for testing purposes 
    public static void overrideImplementation(IClassWithStaticsImpl implementation) { 
    ClassWithStatics.implementation = implementation; 
    } 

    public static Foo someMethod() { 
    return implementation.someMethod(); 
    } 

} 

Ainsi, dans la configuration de vos tests, vous appelez overrideImplementation avec une interface de raillé. L'avantage est que vous n'avez pas besoin de changer les clients de votre classe statique. L'inconvénient est que vous aurez probablement un petit code dupliqué, car vous devrez répéter les méthodes de la classe statique et de son implémentation. Mais parfois, les méthodes statiques peuvent utiliser une interface de base qui fournit une fonctionnalité de base.

+3

Juste un petit point, l'implémentation ne devrait-elle pas être déclarée statique si elle devait être accessible de manière statique? – Grundlefleck

0

Le problème que vous avez est lorsque vous utilisez un code tiers et il est appelé à partir de l'une de vos méthodes. Ce que nous avons fini par faire est de l'emballer dans un objet, et de l'appeler en le passant avec dep inj, et alors votre test unitaire peut simuler une méthode statique tierce appeler le setter avec lui.

Questions connexes