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)));
Это тоже хорошо работает.
Ответы
Ответ 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