Проверить значение атрибута объекта с помощью mockito

У меня есть вызов метода, над которым я хочу поиздеваться с mockito. Для начала я создал и внедрил экземпляр объекта, для которого будет вызываться метод. Моя цель - проверить один из объектов при вызове метода.

Есть ли способ, которым mockito позволяет вам утверждать или проверять объект и его атрибуты при вызове метода mock?

пример

Mockito.verify(mockedObject)
       .someMethodOnMockedObject(
              Mockito.<SomeObjectAsArgument>anyObject())

Вместо того, чтобы делать anyObject(), я хочу проверить, что объект аргумента содержит некоторые определенные поля

Mockito.verify(mockedObject)
       .someMethodOnMockedObject(
              Mockito.<SomeObjectAsArgument>**compareWithThisObject()**)

person Priyank    schedule 17.07.2009    source источник
comment
В качестве альтернативы использованию mockito в этих случаях вы можете рассмотреть возможность создания настраиваемой заглушки, которая расширяет класс mockedObject и переопределяет someMethodOnMockedObject, чтобы сохранить объект для последующего сравнения.   -  person Gonen I    schedule 06.04.2019


Ответы (11)


Новая функция, добавленная в Mockito, делает это еще проще,

ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
verify(mock).doSomething(argument.capture());
assertEquals("John", argument.getValue().getName());

Ознакомьтесь с документацией Mockito.


В случае, когда существует более одного параметра и требуется захват только одного параметра, используйте другие ArgumentMatcher для обертывания остальных аргументов:

verify(mock).doSomething(eq(someValue), eq(someOtherValue), argument.capture());
assertEquals("John", argument.getValue().getName());
person iraSenthil    schedule 15.09.2011
comment
если ваш метод имеет более одного аргумента, вы должны использовать Matchers и для всех остальных аргументов. akcasoy.wordpress.com/tag/argumentcaptor - person robsonrosa; 05.08.2015
comment
Что делать, если есть несколько аргументов? Как указать именно тот, который вас интересует? - person IgorGanapolsky; 24.02.2017
comment
@IgorGanapolsky Предполагая второй параметр String для doSomething, что вам нужно сделать: verify (mock) .doSomething (argument.capture (), anyString ()); - person GreenTurtle; 07.04.2017
comment
необходимость использования сопоставителей для всех аргументов определяется только стандартной спецификацией использования сопоставителей по принципу «все или ничего». - person Charney Kaye; 01.12.2017

Я думаю, что самый простой способ проверить объект аргумента - использовать метод refEq:

Mockito.verify(mockedObject).someMethodOnMockedObject(ArgumentMatchers.refEq(objectToCompareWith));

Его можно использовать, даже если объект не реализует equals(), потому что используется отражение. Если вы не хотите сравнивать некоторые поля, просто добавьте их имена в качестве аргументов для refEq.

person John29    schedule 30.05.2014
comment
это очень элегантный способ, но, к сожалению, org.mockito.Matchers устарел - person ihebiheb; 14.02.2019
comment
@ihebiheb Перемещено в ArgumentMatchers - person Michael; 01.05.2019

Еще одна возможность, если вы не хотите использовать ArgumentCaptor (например, потому что вы также используете заглушки), - это использовать Hamcrest Matchers в сочетании с Mockito.

import org.mockito.Mockito
import org.hamcrest.Matchers
...

Mockito.verify(mockedObject).someMethodOnMockedObject(MockitoHamcrest.argThat(
    Matchers.<SomeObjectAsArgument>hasProperty("propertyName", desiredValue)));
person charleyc    schedule 01.05.2012
comment
Замечание: убедитесь, что пакет Matchers правильный, поскольку написание той же строки кода с классом org.mockito.Matchers вызывает вводящее в заблуждение исключение, в котором говорится, что параметр фиктивной функции просто не совпадает. - person buer; 20.01.2018
comment
Обратите внимание, что в современных версиях Mockito это MockitoHamcrest.argThat(), а не Mockito.argThat() - person Roman Puchkovskiy; 17.07.2019

Это ответ на основе ответа 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"));
    }
}
person Walery Strauch    schedule 09.04.2015
comment
Это будет работать только для одного аргумента в params. - person IgorGanapolsky; 24.02.2017
comment
Вы можете использовать один захват для более чем одного аргумента. Если вы захватили более одного аргумента, вы можете перечислить все результаты с помощью captor.getAllValues(). Метод captor.getValue(), который используется в ответе, дает последний результат. - person Walery Strauch; 24.02.2017

Если вы используете Java 8, вы можете использовать лямбда-выражения для сопоставления.

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/

person GuiSim    schedule 17.03.2016

Упрощенное решение без создания нового класса реализации Matcher и использования лямбда-выражения:

verify(mockObject).someMockMethod(
        argThat((SomeArgument arg) -> arg.fieldToMatch.equals(expectedFieldValue)));
person murali mohan    schedule 19.06.2020
comment
Здесь отсутствует закрывающая скобка, но я не могу отредактировать изменение одного символа. - person Chris R; 22.04.2021
comment
Я добавил недостающую скобу сейчас - person murali mohan; 22.04.2021

Приведенные выше решения в моем случае не сработали. Я не мог использовать ArgumentCaptor, так как метод вызывался несколько раз, и мне нужно было проверить каждый из них. Простой Matcher с argThat легко справился с задачей.

Пользовательское сопоставление

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

Средство выполнения тестов

// 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)));
person whizzle    schedule 09.11.2017

И очень красивое и чистое решение в колтине от com.nhaarman.mockito_kotlin

verify(mock).execute(argThat {
    this.param = expected
})
person Cililing    schedule 06.12.2018

Вы можете сослаться на следующее:

Mockito.verify(mockedObject).someMethodOnMockedObject(eq(desiredObject))

Это позволит проверить, вызывается ли метод mockedObject с параметром desireObject.

person zaid bepari    schedule 07.12.2016

Еще один простой способ сделать это:

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;
            }
        }));
person pierrefevrier    schedule 13.02.2019

В javadoc для refEq упоминается, что проверка на равенство неглубокая! Вы можете найти более подробную информацию по ссылке ниже:

https://static.javadoc.io/org.mockito/mockito-core/2.2.29/org/mockito/ArgumentMatchers.html#refEq(T,%20java.lang.String...)

Проблема поверхностного равенства не может контролироваться при использовании других классов, которые не реализуют метод .equals (), класс DefaultMongoTypeMapper является примером, в котором метод .equals () не реализован.

org.springframework.beans.factory.support предлагает метод, который может генерировать определение bean-компонента вместо создания экземпляра объекта, и его можно использовать, чтобы избавиться от ошибки сравнения.

 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());
person Saif Masadeh    schedule 25.02.2017