[java] Mockito : 바운드 와일드 카드로 유형을 반환하는 스터 빙 방법

이 코드를 고려하십시오.

public class DummyClass {
    public List<? extends Number> dummyMethod() {
        return new ArrayList<Integer>();
    }
}
public class DummyClassTest {
    public void testMockitoWithGenerics() {
        DummyClass dummyClass = Mockito.mock(DummyClass.class);
        List<? extends Number> someList = new ArrayList<Integer>();
        Mockito.when(dummyClass.dummyMethod()).thenReturn(someList); //Compiler complains about this
    }
}

컴파일러는의 동작을 스텁하려는 행에 대해 불평합니다 dummyMethod(). 경계가있는 와일드 카드가있는 유형을 반환하는 스텁 메소드에 대한 포인터가 있습니까?



답변

이 목적을 위해 비 유형 안전 메소드 doReturn 을 사용할 수도 있습니다.

@Test
public void testMockitoWithGenerics()
{
    DummyClass dummyClass = Mockito.mock(DummyClass.class);
    List<? extends Number> someList = new ArrayList<Integer>();

    Mockito.doReturn(someList).when(dummyClass).dummyMethod();

    Assert.assertEquals(someList, dummyClass.dummyMethod());
}

Mockito의 Google 그룹에서 논의한 대로 .

이보다 간단하지만 thenAnswer형식이 안전하지 않습니다. 유형 안전이 염려된다면 millhouse의 대답 이 맞습니다.

추가 세부 사항

명확히하기 위해 관찰 된 컴파일러 오류는 다음과 같습니다.

The method thenReturn(List<capture#1-of ? extends Number>) in the type OngoingStubbing<List<capture#1-of ? extends Number>> is not applicable for the arguments (List<capture#2-of ? extends Number>)

컴파일러가 when호출 중에 첫 번째 와일드 카드 유형을 할당 한 다음 호출의 두 번째 와일드 카드 유형 thenReturn이 동일한 지 확인할 수 없습니다 .

thenAnswer와일드 카드 유형을 허용하는 동안 와일드 카드 유형 thenReturn이 아닌 유형을 사용하므로이 문제가 발생하지 않는 것 같습니다 . Mockito의 OngoingStubbing 에서

OngoingStubbing<T> thenAnswer(Answer<?> answer);
OngoingStubbing<T> thenReturn(T value);


답변

나는 당신이 someList알려진 값 으로로드 할 수 있기를 원한다고 가정 합니다. 다음 Answer<T>은 템플릿 형식의 도우미 메서드와 함께 사용하여 모든 유형을 안전하게 유지하는 방법입니다.

@Test
public void testMockitoWithGenericsUsingAnswer()
{
    DummyClass dummyClass =  Mockito.mock(DummyClass.class);

    Answer<List<Integer>> answer = setupDummyListAnswer(77, 88, 99);
    Mockito.when(dummyClass.dummyMethod()).thenAnswer(answer);

    ...
}

private <N extends Number> Answer<List<N>> setupDummyListAnswer(N... values) {
    final List<N> someList = new ArrayList<N>();

    someList.addAll(Arrays.asList(values));

    Answer<List<N>> answer = new Answer<List<N>>() {
        public List<N> answer(InvocationOnMock invocation) throws Throwable {
            return someList;
        }
    };
    return answer;
}


답변

나는 어제 같은 것을 맞았다. @ nondescript1과 @millhouse의 대답은 해결 방법을 찾는 데 도움이되었습니다. 나는 거의 내 오류가 발생되지 않았기 때문에, 나는 그것이 약간 더 일반적인 만든 것을 제외하고, @millhouse과 같은 코드를 사용했습니다 java.util.List,하지만 com.google.common.base.Optional. 내 작은 도우미 메서드는 다음과 같은 유형 T이 아니라 모든 유형을 허용합니다 List<T>.

public static <T> Answer<T> createAnswer(final T value) {
    Answer<T> dummy = new Answer<T>() {
        @Override
        public T answer(InvocationOnMock invocation) throws Throwable {
            return value;
        }
    };
    return dummy;
}

이 도우미 메서드를 사용하면 다음과 같이 작성할 수 있습니다.

Mockito.when(dummyClass.dummyMethod()).thenAnswer(createAnswer(someList));

이것은 잘 컴파일되고 thenReturn(...)메소드 와 동일한 작업을 수행합니다 .

누군가 Java 컴파일러에서 발생하는 오류가 컴파일러 버그인지 또는 코드가 실제로 잘못된 것인지 알고 있습니까?


답변

Java 8 이상을 사용하는 가장 우아한 솔루션이라고 생각할 때 더 많은 가시성을 제공하기 위해 fikovnik 의 의견 을 여기에 대한 답변 으로 바꾸고 있습니다.

Mockito 설명서를 사용하는 것이 좋습니다 doReturn()(허용 대답에 제안) 마지막 수단으로 만.

대신, 질문에 설명 된 컴파일러 오류를 피하기 위해 권장 Mockito when()접근 방식 thenAnswer()과 람다를 사용할 수 있습니다 (도움말 방법 대신).

Mockito.when(mockedClass.mockedMethod()).thenAnswer(x -> resultList)


답변

Marek Radonsky가 제안한 유틸리티 방법은 효과가 있지만 (IMHO 이상하게 보이는) 람다 식 fikovnik을 요구하지 않는 다른 옵션도 있습니다.

비슷한 질문에 대한 이 답변 에서 알 수 있듯이 다음 을 사용할 수도 있습니다.

BDDMockito.willReturn(someList).given(dummyClass).dummyMethod();


답변