Imaginez le code suivant:
List list = .....
List spy = spy(list);
doThrow(new NullpointerException()).when(spy).get(0);
doThrow(....)
exécute list.get(0)
- cela n'a aucun sens. Je voudrais définir le comportement factice et ne pas appeler une méthode ici ..... quelque chose me manque-t-il?
EDIT: La liste est décorée par CGLIB. Lorsque je supprime le proxy CGLIB, Mockito fonctionne comme prévu. Une idée de comment résoudre ce problème lors de l’utilisation des proxies CGLIB?
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.spy;
import Java.lang.reflect.Method;
import org.junit.Test;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class MockitoSpyTest {
@Test
public void execTest() {
System.out.println("*** TEST 1 ***");
System.out.println("Test on unmodified object");
MySet ms = new MySetImpl();
ms.set("test value");
System.out.println("Set contains: " + ms.get());
// decorate ms1 with easymock
System.out.println("\n*** TEST 2 ***");
MySet spyMs = spy(ms);
doThrow(new NullPointerException("my test nullpointer")).when(spyMs).get();
System.out.println("Test decorated object with SPY");
spyMs.set("test value");
try {
System.out.println("Set contains: " + spyMs.get());
} catch (NullPointerException e) {
System.out.println("NullPointerException - as expected");
}
// Enhance call with CGLIB
System.out.println("\n*** TEST 3 ***");
System.out.println("Test on CGLIB decorated object");
Enhancer enc = new Enhancer();
enc.setSuperclass(MySetImpl.class);
enc.setInterfaces(new Class[] { MySet.class });
enc.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
if ("get".equals(method.getName())) {
System.out.println("CGLIB decorated GET call");
}
return proxy.invokeSuper(obj, args);
}
});
MySet ms1 = (MySet) enc.create();
ms1.set("test value");
System.out.println("Set contains: " + ms1.get());
// decorate ms1 with easymock
System.out.println("\n*** TEST 4 ***");
System.out.println("Test on CGLIB decorated object with SPY");
MySet spyMs1 = spy(ms1);
doThrow(new NullPointerException("my test nullpointer")).when(spyMs1).get();
spyMs1.set("test value");
System.out.println("Set contains: " + spyMs1.get());
}
public interface MySet {
void set(String val);
String get();
}
public static class MySetImpl implements MySet {
String val;
public void set(String val) {
this.val = val;
System.out.println("Original SET call:" + val);
}
public String get() {
System.out.println("Original GET call:" + val);
return val;
}
}
}
L'exemple ci-dessus produit une sortie:
*** TEST 1 ***
Test on unmodified object
Original SET call:test value
Original GET call:test value
Set contains: test value
*** TEST 2 ***
Test decorated object with SPY
Original SET call:test value
NullPointerException - as expected
*** TEST 3 ***
Test on CGLIB decorated object
Original SET call:test value
CGLIB decorated GET call
Original GET call:test value
Set contains: test value
*** TEST 4 ***
Test on CGLIB decorated object with SPY
CGLIB decorated GET call
Original GET call:test value
Original SET call:test value
CGLIB decorated GET call
Original GET call:test value
Set contains: test value
Maintenant, le TEST 2
et le TEST 4
devraient lancer NullPointerException
sur un appel get
- basé sur l'espion mockito: doThrow(new NullPointerException("my test nullpointer")).when(spyMs1).get();
Le "TEST 4" ne lance pas l'exception attendue car il est déjà décoré avec CGLIB - nous pouvons également voir sur la console que l'appel CGLIb est en cours d'exécution: GLIB decorated GET call
et ne pas appeler d'objet espion. Le même effet peut être obtenu lorsque vous utilisez Spring AOP avec des mandataires CGLIB.
Mockito.doThrow(new NullpointerException()).when(spy).get(0);
Je pense que le problème ici est que vous essayez de faire une simulation partielle et que vous devez donc avoir l'annotation sur votre classe de test:
@PrepareForTest(List.class)
Cela peut ou peut ne pas fonctionner. En examinant mon code où je teste la gestion des exceptions, je l’ai toujours fait sur un objet totalement fictif, et non partiellement fictif. De plus, j’ai beaucoup utilisé PowerMockito lorsqu’il s’est moqué, il est donc possible que la bibliothèque fasse tout ce dont vous avez besoin.