Есть ли способ в JMockit для вызова исходного метода из смоделированного метода?

В моем фиктивном классе я использую метод foo (). В некоторых тестовых случаях я хочу, чтобы фиктивная реализация foo () возвращала специальное значение. Для других тестовых случаев я хочу использовать реальную реализацию foo (). У меня есть логическое значение, определенное в моём классе, чтобы я мог определить в методе макета, хочу ли я вернуть специальное значение или использовать «настоящий» метод. Проблема в том, что я не могу понять, как вызвать реальный метод из смоделированного метода.

Я обнаружил, что вы можете определить специальный элемент в фиктивном объекте с именем "it" (с типом объекта, который будет насмехаться). Это позволяет вам ссылаться на реальный класс из фиктивной реализации. Итак, мой план состоял в том, чтобы, если бы мне нужно было вызвать «реальную» реализацию foo (), метод mock вызвал бы его.foo (). Тем не менее, это не работает, потому что вызов it.foo () просто снова вызывает фиктивную версию, а не реальную версию, поэтому я получаю бесконечную рекурсию.

Есть ли способ сделать эту работу?

РЕДАКТИРОВАТЬ: это может быть яснее с примером кода, вот как выглядит моя текущая реализация смоделированного метода:

private RealClass it;
...
public SomeClass foo() {
    if(fakeIt) {
        return new SomeClass("fakevalue");
    } else {
        // doesn't work, just keeps calling the mock foo
        // in infinite recursion
        return it.foo();
    }
}

РЕДАКТИРОВАТЬ 2: Кроме того, для большинства моих тестовых случаев я не хочу имитировать реализацию. Поэтому моя первоначальная попытка была в том, чтобы вызывать Mockit.redefineMethods () только в тех тестовых случаях, где мне был нужен фиктивный объект. Но это не сработало - кажется, вы можете сделать это только в рамках установки / разрыва ... моя пробная реализация никогда не вызывалась, когда я пытался это сделать.

ЗАМЕЧАНИЯ ПО РЕШЕНИЮ:

Сначала я не думал, что полученный ответ сработал, но, поиграв с ним еще раз, кажется, проблема в том, что я смешивал «основные» методы JMockit с методами, «управляемыми аннотациями». Очевидно, что при использовании аннотации вам нужно использовать Mockit.setupMocks, а не Mockit.redefineMethods (). Вот что наконец сработало:

@Before 
public void setUp() throws Exception
{
    Mockit.setUpMocks(MyMockClass.class);
}

Тогда для ложного класса:

@MockClass(realClass = RealClass.class)
public static class MyMockClass {
    private static boolean fakeIt = false;
    private RealClass it;

    @Mock(reentrant = true)
    public SomeClass foo() {
        if(fakeIt) {
            return new SomeClass("fakevalue");
        } else {
            return it.foo();
        }
    }
}
10.12.2008 18:49:13
3 ОТВЕТА
РЕШЕНИЕ

Я думаю, что вы можете сделать это с @Mockаннотацией. Из документации, @Mock(reentrant=true)на вашем макете класс должен это сделать.

См. Http://jmockit.googlecode.com/svn/trunk/www/javadoc/mockit/Mock.html.
Пример можно посмотреть здесь http://jmockit.googlecode.com/svn/trunk/www/tutorial/StateBasedTesting.html. #reentrant

Я не проверял это хотя ..

8
8.11.2011 15:14:54
Я должен что-то упустить. Из документа это звучит многообещающе, но не имеет значения, использую ли я reentrent = true или false, я получаю то же поведение, что и раньше. Также в документе написано «По умолчанию такие вызовы запрещены, потому что они приводят к бесконечной рекурсии ...», поэтому я запутался.
Eric Asberry 11.12.2008 15:38:20
После дальнейшего рассмотрения я нашел то, что мне не хватало :)
Eric Asberry 11.12.2008 16:12:51
Я обновил ссылку JavaDoc и добавил пример ссылки. +1 за ответ.
Tobias Sarnow 8.11.2011 15:04:03
Ссылки не работают, как это было более 6 лет.
demongolem 3.02.2015 16:26:29
Я думаю, что стоит отметить, что этот ответ был действителен только тогда, когда на вопрос был дан ответ. С тех пор это не рекомендуется в API JMockit в более поздних версиях JMockit. Ответ, данный Тревором Робинсоном, теперь лучший ответ, imo. Этот ответ остается в силе, только если вы используете старую версию JMockit.
searchengine27 19.12.2016 19:10:54

Вместо добавления фиктивного объекта вы также можете создать подкласс для объекта, который вы хотите протестировать, и переопределить методы, которые должны возвращать специальные значения.

Например:

RealClass toTest = new RealClass(){
      public String foo(){
          return "special value";
      }
}

//use toTest in test

Сохраняя это определение в своем тесте, другим также становится ясно, какие методы «высмеиваются».

1
10.12.2008 20:07:27
Спасибо за предложение! К сожалению, я не могу использовать этот подход, потому что класс, над которым я издеваюсь, на самом деле не создается непосредственно тестовым примером. Он был создан объектом, который тестируется.
Eric Asberry 10.12.2008 20:25:08

В более поздних версиях JMockit Invocation.proceed()может вызываться из MockUpреализации. См. Подделка: переход к реальной реализации .

public class MyMockClass extends MockUp<RealClass> {

    private static boolean fakeIt = false;

    @Mock
    public SomeClass foo(Invocation inv) {
        if (fakeIt) {
            return new SomeClass("fakevalue");
        } else {
            return inv.proceed();
        }
    }
}
9
3.05.2017 16:53:24