Подтвердить что ты не робот

Mockito - шпионаж на реальные объекты вызывает оригинальный метод

Представьте следующий код:

List list = .....
List spy = spy(list);
doThrow(new NullpointerException()).when(spy).get(0);

doThrow(....) выполняет list.get(0) - это не имеет никакого смысла. Я хотел бы определить макет поведения и не вызывать метод здесь..... я что-то не хватает?

EDIT: Список украшен CGLIB. Когда я удаляю прокси-сервер CGLIB, Mockito работает так, как ожидалось. Любая идея, как решить эту проблему при использовании прокси CGLIB?

Спасибо, Maciej

4b9b3361

Ответ 1

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;
        }

    }
}

Пример выше дает результат:

*** 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

Теперь TEST 2 и TEST 4 должны бросать NullPointerException на вызов get на основе mockito spy: doThrow(new NullPointerException("my test nullpointer")).when(spyMs1).get();

"TEST 4" не генерирует ожидаемое исключение, поскольку оно уже украшено CGLIB. На консоли также можно увидеть, что выполняется вызов CGLIb: GLIB decorated GET call и не вызывать объект-шпион. Тот же эффект может быть достигнут при использовании Spring АОП с проксими CGLIB.

Ответ 2

Mockito.doThrow(new NullpointerException()).when(spy).get(0);

Я думаю, проблема здесь в том, что вы пытаетесь сделать частичный макет, и поэтому вам нужно иметь аннотацию в тестовом классе:

@PrepareForTest(List.class)

Это может работать или не работать. Глядя на мой код, где я тестирую обработку исключений, я всегда делал это на полностью издеваемом объекте, а не на частичном издевательстве. Кроме того, я широко использовал PowerMockito, когда частично насмешливо, поэтому возможно, что библиотека сделает то, что вам нужно.