Mockito UnfinishedStubbingException - программирование
Подтвердить что ты не робот

Mockito UnfinishedStubbingException

Я новичок в Mockito, я попытался изучить это исключение, но я не нашел конкретного ответа. Это происходит в моем коде, когда я использую два макета вместе, что означает, что я передаю конструктор макета, еще один макет. Например:

...
OperationNode child = getNode(Operation.ADD);
child.insertNode(getConstantNode(getIntegerValue(2));
...

 private ConstantNode getConstantNode(NumericalValue value){
    ConstantNode node = Mockito.mock(ConstantNode.class);
    Mockito.when(node.evaluate()).thenReturn(value);
    Mockito.when(node.toString()).thenReturn(value.toString());
    return node;
}

private IntegerValue getIntegerValue(int number) {
   IntegerValue integerValue = Mockito.mock(IntegerValue.class);
   Mockito.when(integerValue.getValue()).thenReturn(number);
   Mockito.when(integerValue.toString()).thenReturn(Integer.toString(number));
   return integerValue;
}

На одном из форумов, который я читал о том, чтобы не отправлять макет через конструктор другого макета, поскольку Mockito может запутаться с макетными вызовами, поэтому я попробовал следующее:

NumericalValue value = getIntegerValue(2);
child.insertNode(getConstantNode(value));

Но безрезультатно. Я убеждаюсь, что вызываются только методы toString() и getValue(), потому что это единственные методы, которые имеет класс. Я не понимаю, что происходит.

Я также пытался использовать макеты отдельно, чтобы убедиться, что я сделал что-то не так:

child.insertNode(new ConstantNode(getIntegerValue(2)));

Это работает отлично.

child.insertNode(getConstantNode(new IntegerValue(2)));

Это тоже хорошо работает.

4b9b3361

Ответ 1

Из того, что я читал в "Проблема 53" mockito (https://code.google.com/p/mockito/issues/detail?id=53), мой код испытывал проблему из-за структуры проверки участвовал в Mockito. Именно следующий код вызывал исключение как таковое.

private ConstantNode getConstantNode(NumericalValue value){
    ConstantNode node = Mockito.mock(ConstantNode.class);
    Mockito.when(node.evaluate()).thenReturn(value);
    Mockito.when(node.toString()).thenReturn(value.toString());
    return node;
}

Если вы помните из моего кода, значение параметра ALSO A MOCK, так что, когда value.toString() вызывается в thenReturn(), я верю (и кто-то, пожалуйста, исправьте меня, если я ошибаюсь), что структура проверки запускается и гарантирует, что каждый "когда" имеет свой thenReturn(), называемый/проверенный/etc. Итак, если это произойдет, Mockito.when(node.toString()).thenReturn(value.toString() не будет проверяться, потому что он не вернулся из valute.toString(), который запустил целую цепочку "проверять все".

Как я его исправил:

private ConstantNode getConstantNode(NumericalValue value){
    ConstantNode node = Mockito.mock(ConstantNode.class);
    Mockito.when(node.evaluate()).thenReturn(value);

    String numberToString = value.toString();

    Mockito.when(node.toString()).thenReturn(numberToString);
    return node;
}

Таким образом, он может проверяться. Я нахожу этот полный запах кода, потому что мне буквально придется оставить комментарий, который объясняет, почему я использую, казалось бы, бесполезную промежуточную переменную в коде.

Спасибо за помощь.

Ответ 2

В этом вопросе уже есть хорошие исправления, но для тех, кто все еще не понимает этого, подумайте о порядке, в котором Java вызывает все эти методы. Согласно Java Language Specification, Java оценивает каждый параметр метода left- перед вызовом метода:

  • integerValue.getValue(), который Mockito записывает
  • when, где Mockito принимает последний вызов (до integer.getValue) и начинает настройку
  • value.toString, который является издеваемым вызовом, который Mockito записывает
  • thenReturn на stubber

Mockito жалуется точно, потому что вызов макета, шаг 3, происходит после шага 2 (when), но до шага 4 (thenReturn), заставляя систему проверки жаловаться на ступицу. Радость, ваш ответ перемещает сложный шаг 3 до этапа 1, и это нормально; Саджан полностью удаляет его из утверждения, что тоже прекрасно.

Ответ 3

Я думаю, проблема связана с линией

Mockito.when(node.toString()).thenReturn(value.toString()); в методе getConstantNode

Попробуйте удалить строку и проверить, не работает ли она. Может быть, вы можете сделать что-то вроде

int num = 2;
child.insertNode(getConstantNode(getIntegerValue(num), num);
...

 private ConstantNode getConstantNode(NumericalValue value){
    ConstantNode node = Mockito.mock(ConstantNode.class);
    Mockito.when(node.evaluate()).thenReturn(value);
    Mockito.when(node.toString()).thenReturn(Integer.toString(number));
    return node;
}

private IntegerValue getIntegerValue(int number) {
   IntegerValue integerValue = Mockito.mock(IntegerValue.class);
   Mockito.when(integerValue.getValue()).thenReturn(number);
   return integerValue;
}

Ответ 4

Я думаю, что это проблема с заказом вызовов и проверкой Mockito Framework. Попробуйте это и посмотрите, помогает ли это:

...
OperationNode child = getNode(Operation.ADD);
IntegerValue value = getIntegerValue(2);
ConstantNode node =  Mockito.mock(ConstantNode.class);
Mockito.when(node.evaluate()).thenReturn(value);
Mockito.when(node.toString()).thenReturn(value.toString());
child.insertNode(node);

...

private IntegerValue getIntegerValue(int number) {
   IntegerValue integerValue = Mockito.mock(IntegerValue.class);
   Mockito.when(integerValue.getValue()).thenReturn(number);
   Mockito.when(integerValue.toString()).thenReturn(Integer.toString(number));
   return integerValue;
}

Источник: https://code.google.com/p/mockito/issues/detail?id=53