Ответ 1
http://sites.google.com/a/pintailconsultingllc.com/java/argument-matching-with-mockito
Эта ссылка содержит рабочий пример. Я смог решить эту проблему с той же стратегией.
У меня есть вызов метода, который я хочу издеваться над mockito. Для начала я создал и ввел экземпляр объекта, на который будет вызываться метод. Моя цель - проверить один из объектов в вызове метода.
Есть ли способ, с помощью которого mockito позволяет утверждать или проверять объект, и он атрибут при вызове метода макета?
Пример
Mockito.verify(mockedObject)
.someMethodOnMockedObject(
Mockito.<SomeObjectAsArgument>anyObject())
Вместо выполнения anyObject()
я хочу проверить, что объект аргумента содержит определенные поля
Mockito.verify(mockedObject)
.someMethodOnMockedObject(
Mockito.<SomeObjectAsArgument>**compareWithThisObject()**)
http://sites.google.com/a/pintailconsultingllc.com/java/argument-matching-with-mockito
Эта ссылка содержит рабочий пример. Я смог решить эту проблему с той же стратегией.
Новая функция, добавленная в Mockito, делает это еще проще,
ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
verify(mock).doSomething(argument.capture());
assertEquals("John", argument.getValue().getName());
Взгляните на документацию Mockito
В случае, когда имеется более одного параметра и требуется захват только одного параметра, используйте другие ArgumentMatchers, чтобы обернуть остальные аргументы:
verify(mock).doSomething(eq(someValue), eq(someOtherValue), argument.capture());
assertEquals("John", argument.getValue().getName());
Я думаю, что самый простой способ проверки объекта аргумента - использовать метод refEq
:
Mockito.verify(mockedObject).someMethodOnMockedObject(Matchers.refEq(objectToCompareWith));
Он может использоваться, даже если объект не реализует equals()
, потому что используется отражение. Если вы не хотите сравнивать некоторые поля, просто добавьте их имена в качестве аргументов для refEq
.
Еще одна возможность, если вы не хотите использовать ArgumentCaptor
(например, потому что вы также используете stubbing), заключается в использовании Hamcrest Matchers в сочетании с Mockito.
import org.mockito.Mockito
import org.hamcrest.Matchers
...
Mockito.verify(mockedObject).someMethodOnMockedObject(Mockito.argThat(
Matchers.<SomeObjectAsArgument>hasProperty("propertyName", desiredValue)));
Это ответ, основанный на ответе от iraSenthil, но с аннотацией (Captor). По моему мнению, это имеет некоторые преимущества:
Пример:
@RunWith(MockitoJUnitRunner.class)
public class SomeTest{
@Captor
private ArgumentCaptor<List<SomeType>> captor;
//...
@Test
public void shouldTestArgsVals() {
//...
verify(mockedObject).someMethodOnMockedObject(captor.capture());
assertThat(captor.getValue().getXXX(), is("expected"));
}
}
Если вы используете Java 8, вы можете использовать выражения Lambda для соответствия.
import java.util.Optional;
import java.util.function.Predicate;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
public class LambdaMatcher<T> extends BaseMatcher<T>
{
private final Predicate<T> matcher;
private final Optional<String> description;
public LambdaMatcher(Predicate<T> matcher)
{
this(matcher, null);
}
public LambdaMatcher(Predicate<T> matcher, String description)
{
this.matcher = matcher;
this.description = Optional.ofNullable(description);
}
@SuppressWarnings("unchecked")
@Override
public boolean matches(Object argument)
{
return matcher.test((T) argument);
}
@Override
public void describeTo(Description description)
{
this.description.ifPresent(description::appendText);
}
}
Пример вызова
@Test
public void canFindEmployee()
{
Employee employee = new Employee("John");
company.addEmployee(employee);
verify(mockedDal).registerEmployee(argThat(new LambdaMatcher<>(e -> e.getName()
.equals(employee.getName()))));
}
Дополнительная информация: http://source.coveo.com/2014/10/01/java8-mockito/
Вышеупомянутые решения на самом деле не работали в моем случае. Я не мог использовать ArgumentCaptor, поскольку метод вызывался несколько раз, и мне нужно было проверить его. Простой Matcher с "argThat" легко справился.
Пользовательский Matcher
// custom matcher
private class PolygonMatcher extends ArgumentMatcher<PolygonOptions> {
private int fillColor;
public PolygonMatcher(int fillColor) {
this.fillColor = fillColor;
}
@Override
public boolean matches(Object argument) {
if (!(argument instanceof PolygonOptions)) return false;
PolygonOptions arg = (PolygonOptions)argument;
return Color.red(arg.getFillColor()) == Color.red(fillColor)
&& Color.green(arg.getFillColor()) == Color.green(fillColor)
&& Color.blue(arg.getFillColor()) == Color.blue(fillColor);
}
}
Test Runner
// do setup work setup
// 3 light green polygons
int green = getContext().getResources().getColor(R.color.dmb_rx_bucket1);
verify(map, times(3)).addPolygon(argThat(new PolygonMatcher(green)));
// 1 medium yellow polygons
int yellow = getContext().getResources().getColor(R.color.dmb_rx_bucket4);
verify(map, times(1)).addPolygon(argThat(new PolygonMatcher(yellow)));
// 3 red polygons
int orange = getContext().getResources().getColor(R.color.dmb_rx_bucket5);
verify(map, times(3)).addPolygon(argThat(new PolygonMatcher(orange)));
// 2 red polygons
int red = getContext().getResources().getColor(R.color.dmb_rx_bucket7);
verify(map, times(2)).addPolygon(argThat(new PolygonMatcher(red)));
И очень приятное и чистое решение в колтине от com.nhaarman.mockito_kotlin
verify(mock).execute(argThat {
this.param = expected
})
Вы можете указать следующее:
Mockito.verify(mockedObject).someMethodOnMockedObject(eq(desiredObject))
Это проверит, вызывается ли метод mockedObject с параметром wishObject в качестве параметра.
Еще один простой способ сделать это:
import org.mockito.BDDMockito;
import static org.mockito.Matchers.argThat;
import org.mockito.ArgumentMatcher;
BDDMockito.verify(mockedObject)
.someMethodOnMockedObject(argThat(new ArgumentMatcher<TypeOfMethodArg>() {
@Override
public boolean matches(Object argument) {
final TypeOfMethodArg castedArg = (TypeOfMethodArg) argument;
// Make your verifications and return a boolean to say if it matches or not
boolean isArgMarching = true;
return isArgMarching;
}
}));
В javadoc для refEq указано, что проверка равенства неглубокая! Вы можете найти более подробную информацию по ссылке ниже:
Проблема "неглубокого равенства" не может контролироваться при использовании других классов, которые не реализуют метод .equals(), класс DefaultMongoTypeMapper - это пример, где метод .equals() не реализован.
org.springframework.beans.factory.support предлагает метод, который может генерировать определение bean вместо создания экземпляра объекта, и его можно использовать для git избавления от ошибки сравнения.
genericBeanDefinition(DefaultMongoTypeMapper.class)
.setScope(SCOPE_SINGLETON)
.setAutowireMode(AUTOWIRE_CONSTRUCTOR)
.setLazyInit(false)
.addConstructorArgValue(null)
.getBeanDefinition()
** "Определение bean - это только описание bean, а не самого bean. описания bean должным образом реализуют equals() и hashCode(), поэтому вместо создания нового DefaultMongoTypeMapper() мы предоставляем определение, которое сообщает spring, как он должен создать один
В вашем примере вы можете сделать что-то вроде этого
Mockito.verify(mockedObject)
.doSoething(genericBeanDefinition(YourClass.class).setA("a")
.getBeanDefinition());