web-dev-qa-db-fra.com

Comment se moquer des méthodes statiques?

Je suis nouveau dans la simulation d'objets, mais je comprends que j'ai besoin que mes classes implémentent des interfaces afin de les simuler.

Le problème que j'ai, c'est que dans ma couche d'accès aux données, je veux avoir des méthodes statiques, mais je ne peux pas mettre de méthode statique dans une interface.

Quelle est la meilleure façon de contourner cela? Dois-je simplement utiliser des méthodes d'instance (ce qui semble incorrect) ou existe-t-il une autre solution?

34
brien

J'utiliserais un modèle d'objet de méthode. Ayez une instance statique de ceci et appelez-la dans la méthode statique. Il devrait être possible de sous-classer pour les tests, en fonction de votre cadre de simulation.

c'est-à-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 un objet très simple et facile à tester:

public class MethodObject {
    public void doSomething() {
        // do your thang
    }
}
22
Grundlefleck

J'ai trouvé un blog via google avec quelques bons exemples sur la façon de procéder:

  1. Refactorisez la classe pour qu'elle soit une classe d'instance et implémentez une interface.

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

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

    En faisant cela, vous pouvez simuler une interface statique via des délégués.

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

    C'est probablement le plus facile à simuler/gérer sans refactorisation car il peut simplement être hérité et étendu.

26
Rick Minerich

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." La moquerie repose sur le polymorphisme.

Maintenant, si vos méthodes statiques ne se soucient pas logiquement de l'implémentation que vous utilisez, elles pourraient peut-être prendre les interfaces comme paramètres, ou peut-être fonctionner sans interagir avec l'état du tout - mais sinon, vous devriez utiliser des instances (et probablement injection de dépendances pour tout câbler).

26
Jon Skeet

Vous essayez peut-être de tester à un point de départ trop profond. Il n'est pas nécessaire de créer un test 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 tour à tour les méthodes privées et statiques.

Alors disons 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 par rapport à la méthode TransformData (et vous ne pouvez pas). À la place, écrivez un test pour la méthode GetData qui teste le travail effectué dans TransformData.

5
Carlton Jenke

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

Utilisez public static Func [T, U] (références de fonction statiques qui peuvent être remplacées par des fonctions simulées) lorsque les méthodes d'instance ne sont pas possibles.

4
Amy B

Une solution simple est de permettre de changer l'implémentation 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();
  }

}

Donc, dans la configuration de vos tests, vous appelez overrideImplementation avec une interface fictive. 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 peu de code dupliqué, car vous devrez répéter les méthodes de la classe statique et son implémentation. Mais parfois, les méthodes statiques peuvent utiliser une interface plus légère qui fournit une fonctionnalité de base.

0
asterite

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

0
dstarh