mockito를 사용하여 객체 속성 값 확인


264

mockito로 조롱하려는 메소드 호출이 있습니다. 먼저 메소드를 호출 할 객체의 인스턴스를 생성하고 주입했습니다. 내 목표는 메소드 호출에서 객체 중 하나를 확인하는 것입니다.

mockito를 사용하여 mock 메소드가 호출 될 때 객체와 객체의 속성을 주장하거나 확인할 수있는 방법이 있습니까?

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

대신에 anyObject()인수 객체에 특정 필드가 포함되어 있는지 확인하고 싶습니다.

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

이 경우 mockito를 사용하는 대신 mockedObject의 클래스를 확장하고 나중에 비교할 수 있도록 객체를 저장하기 위해 someMethodOnMockedObject를 재정의하는 사용자 지정 스텁을 만드는 것을 고려할 수 있습니다.
Gonen I

답변:


539

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());

1
메소드에 둘 이상의 인수가있는 경우 다른 모든 인수에도 Matcher를 사용해야합니다. akcasoy.wordpress.com/tag/argumentcaptor
robsonrosa

1
인수가 여러 개인 경우 어떻게합니까? 관심있는 정확한 것을 어떻게 지정합니까?
IgorGanapolsky

2
@IgorGanapolsky doSomething에 대한 두 번째 문자열 매개 변수를 가정하면 다음을 수행해야합니다. verify (mock) .doSomething (argument.capture (), anyString ());
GreenTurtle

모든 인수에 대해 매처를 사용할 필요는 전적으로 표준 올인원 또는 매번의 매처 사용 스펙에 따른 것입니다.
Charney Kaye

54

인수 객체를 확인하는 가장 쉬운 방법은 refEq메소드 를 사용하는 것입니다.

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

equals()리플렉션이 사용되기 때문에 객체가 구현하지 않아도 사용할 수 있습니다 . 일부 필드를 비교하지 않으려면 해당 필드의 이름을에 대한 인수로 추가하십시오 refEq.


1
그것은 매우 우아한 방법이지만 불행히도 org.mockito.Matchers는 더 이상 사용되지 않습니다
ihebiheb

5
@ihebiheb 그것은 ArgumentMatchers로 옮겨졌습니다
Michael

48

사용하지 않으려는 경우 ArgumentCaptor(예 : 스터 빙도 사용하기 때문에) 햄 크레스트 매처를 Mockito와 함께 사용하는 것이 하나 더 있습니다.

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

Mockito.verify(mockedObject).someMethodOnMockedObject(MockitoHamcrest.argThat(
    Matchers.<SomeObjectAsArgument>hasProperty("propertyName", desiredValue)));

2
참고 사항 : 클래스로 Matchers동일한 코드 줄을 작성 org.mockito.Matchers하면 모의 함수의 매개 변수가 단순히 일치하지 않는다는 잘못된 예외가 발생 하므로 패키지가 올바른지 확인하십시오 .
buer

1
현대 Mockito 버전에서는 MockitoHamcrest.argThat()그렇지 않습니다.Mockito.argThat()
Roman Puchkovskiy

17

이것은 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"));
    }
}

이것은 params의 단일 인수에 대해서만 작동합니다.
IgorGanapolsky

둘 이상의 인수에 대해 하나의 캡처자를 사용할 수 있습니다. 둘 이상의 인수를 캡처하면을 사용하여 모든 결과를 나열 할 수 있습니다 captor.getAllValues(). captor.getValue()답변에 사용 된 방법 은 마지막 결과를 제공합니다.
Walery Strauch

11

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/


5

위의 솔루션은 실제로 제 경우에는 효과가 없었습니다. 메소드가 여러 번 호출되었으므로 ArgumentCaptor를 사용할 수 없었으며 각 메소드를 검증해야했습니다. "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)));

3

콜틴의 아주 좋고 깨끗한 해결책은 com.nhaarman.mockito_kotlin

verify(mock).execute(argThat {
    this.param = expected
})

1

다음을 참조 할 수 있습니다.

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

이것은 mockedObject의 메소드가 desiredObject를 매개 변수로 사용하여 호출되는지 여부를 확인합니다.


1

그렇게하는 또 다른 쉬운 방법 :

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

0

refEq의 javadoc은 평등 검사가 얕다 고 언급했습니다! 자세한 내용은 아래 링크를 참조하십시오.

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

.equals () 메소드를 구현하지 않는 다른 클래스를 사용하는 경우 "shallow equality"문제를 제어 할 수 없습니다. "DefaultMongoTypeMapper"클래스는 .equals () 메소드가 구현되지 않은 예입니다.

org.springframework.beans.factory.support는 객체의 인스턴스를 생성하는 대신 빈 정의를 생성 할 수있는 메소드를 제공하며 비교 실패를 제거하는 데 사용할 수 있습니다.

 genericBeanDefinition(DefaultMongoTypeMapper.class)
                        .setScope(SCOPE_SINGLETON)
                        .setAutowireMode(AUTOWIRE_CONSTRUCTOR)
                        .setLazyInit(false)
                        .addConstructorArgValue(null)
                        .getBeanDefinition()

** "bean 정의는 bean 자체가 아니라 bean에 대한 설명 일뿐입니다. bean 설명은 equals () 및 hashCode ()를 올바르게 구현하므로 새 DefaultMongoTypeMapper ()를 작성하는 대신 스프링에 방법을 알려주는 정의를 제공합니다. 하나를 만들어야합니다 "

귀하의 예에서는 다음과 같이 somethong 할 수 있습니다

Mockito.verify(mockedObject)
       .doSoething(genericBeanDefinition(YourClass.class).setA("a")
       .getBeanDefinition());

0

새로운 Matcher 구현 클래스를 작성하지 않고 람다 식을 사용하지 않는 단순화 된 솔루션 :

        verify(mockObject).someMockMethod(argThat((SomeArgument arg) -> arg.fieldToMatch.equals(expectedFieldValue));
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.