1

J'ai une classe de base qui ressemble à ceci:Comment Mock et vérifier une méthode de ScheduledExcecutorService être appelé dans la classe des enfants

public abstract class BaseClass implements Runnable { 
final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); 

@Override 
public void run() { 
    someFunction(); 
} 
protected abstract void someFunction(); 
} 

Alors j'ai un quelque chose comme la classe enfant ceci:

public class ChildClass extends BaseClass { 
functionNeedsToBeTested() { 
    scheduler.scheduleAtFixedRate(this, 0L, 5L, TimeUnit.HOURS) 
} 
someFunction() { 
    //Does Something 
} 
} 

Maintenant, le problème vient ici quand j'essaie d'écrire un test que je ne suis pas en mesure de vérifier l'appel de la méthode scheduleAtFixedRate. Mon test ressemble à ceci:

@RunWith(MockitoJUnitRunner.class) 
public class TestClass { 
@Mock 
private ScheduledExecutorService scheduler; 

@InjectMocks 
private ChildClass obj; 

@Test 
public void testFunc() { 
    obj.functionNeedsToBeTested(); 
    Mockito.verify(scheduler).scheduleAtFixedRate(Mockito.any(ChildClass.class, Mockito.anyLong(), Mockito.anyLong(), Mockito.any(TimeUnit.class))); 
} 
} 

test me donne cette erreur:

junit.framework.AssertionFailedError: 
    Wanted but not invoked: 
    scheduler.scheduleAtFixedRate(
     <any>, 
     <any>, 
     <any>, 
     <any> 
    ); 

Répondre

3

Dans votre test, un planificateur fictif est créé, mais il n'est pas utilisé par l'objet sous test.

Vous pouvez rendre la méthode testable si vous injectez le planificateur au lieu d'en instancier un dans la classe de base. Vous pourriez avoir besoin du planificateur comme argument pour le constructeur BaseClass, par exemple

+0

Merci, cela fonctionne de cette façon, mais je me demandais s'il y avait un moyen de tester ce code exact sans modifier le code et en modifiant simplement le test! ! –

+0

@ManthanJamdagni Je suppose que vous pourriez utiliser la réflexion pour remplacer l'exécuteur en utilisant la réflexion, avec https://docs.oracle.com/javase/7/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible(java.lang .reflect.AccessibleObject [],% 20boolean) pour l'annuler étant final. Cependant, l'injection de l'exécuteur au lieu de l'utilisation d'un codeur dur est sans doute une meilleure conception, puisque votre BaseClass peut maintenant fonctionner avec n'importe quel exécuteur donné. Voir https://en.m.wikipedia.org/wiki/Dependency_inversion_principle pour une explication détaillée – CrimsonCricket