Mockito'yu aynı argümanla aynı yönteme birden fazla çağrı ile kullanma


289

Saplanmış bir yöntemin sonraki çağrılarda farklı nesneler döndürmesinin bir yolu var mı? Bunu, bir alandaki belirsiz yanıtları test etmek için yapmak istiyorum ExecutorCompletionService. yani yöntemlerin dönüş sırasına bakılmaksızın sonucun sabit kaldığını test etmek.

Test etmek istediğim kod böyle görünüyor.

// Create an completion service so we can group these tasks together
ExecutorCompletionService<T> completionService =
        new ExecutorCompletionService<T>(service);

// Add all these tasks to the completion service
for (Callable<T> t : ts)
    completionService.submit(request);

// As an when each call finished, add it to the response set.
for (int i = 0; i < calls.size(); i ++) {
    try {
        T t = completionService.take().get();
        // do some stuff that I want to test
    } catch (...) { }        
}

Yanıtlar:


254

Bunu thenAnswer(ile zincirleme yaparken when) yöntemini kullanarak yapabilirsiniz :

when(someMock.someMethod()).thenAnswer(new Answer() {
    private int count = 0;

    public Object answer(InvocationOnMock invocation) {
        if (count++ == 1)
            return 1;

        return 2;
    }
});

Veya eşdeğer, statik doAnsweryöntemi kullanarak :

doAnswer(new Answer() {
    private int count = 0;

    public Object answer(InvocationOnMock invocation) {
        if (count++ == 1)
            return 1;

        return 2;
    }
}).when(someMock).someMethod();

635

Peki ya

when( method-call ).thenReturn( value1, value2, value3 );

Tamamen doğru tür olması koşuluyla, thenReturn köşeli parantezlerine istediğiniz kadar argüman koyabilirsiniz. İlk değer, yöntem ilk çağrıldığında, daha sonra ikinci cevap vb. İle döndürülür. Tüm diğer değerler kullanıldıktan sonra son değer tekrar tekrar döndürülecektir.


4
Bu bir sahte ile çalışır, ancak bir casus ile çalışmaz. Orijinal yöntemin çağrılmasını önlemek istiyorsanız doAnswer (...). When (someSpy) .someMethod (...).
Yuri

6
@Yuri - tam olarak değil. doAnswerBahsettiğiniz bir Answerdurumda bir yazmaya gerek yoktur . Sadece kullanabilirsiniz doReturn(...).when(someSpy).someMethod(...). Emma'nın casuslardan ziyade alaylarla ilgilendiğini varsaymak makul görünüyor, ama sanırım bunu açıklamak için cevabıma bir şeyler ekleyebilirim. Yorum için teşekkürler.
Dawood ibn Kareem

@DawoodibnKareem diyelim ki ilk arama için bir değer döndürmek istiyorum ve ikinci arama için bir İstisna atmak istiyorum. Bu nasıl yapılabilir?
Rito

@Rito Lütfen Volodymyr'in cevabını veya Raystorm'un cevabını okuyun. İkisi de bu davayı kapsıyor.
Dawood ibn Kareem

Böyle görkemli bir cevap.
wild_nothing

151

Daha önce belirtildiği gibi, neredeyse tüm çağrılar zincirlenebilir.

Böylece arayabilirsin

when(mock.method()).thenReturn(foo).thenReturn(bar).thenThrow(new Exception("test"));

//OR if you're mocking a void method and/or using spy instead of mock

doReturn(foo).doReturn(bar).doThrow(new Exception("Test").when(mock).method();

Mockito's Documenation hakkında daha fazla bilgi .


3
Çok yararlı! mock.methodBu örnekte 4. kez ne denirdi? Bir şey istiyorum, foo ilk kez dönmek ama geri kalanı için geri kalanı.
javaPlease42

6
Sahte her ek çağrı son 'thenReturn' veya son 'thenThrow' geri dönecek Çok yararlı
Francois Lacoursiere

Harika ve basit talimatlar için teşekkür ederim. Bunu şimdiye kadar hiç bilmiyordum. İki özdeş çağrıda iki farklı sonucun nasıl geri alınacağını bulmak için uğraşıyordum. Bana tonlarca zaman kazandır.
CharlesC

68

Bunun doReturn()gibi yöntem çağrılarını bile zincirleyebilirsiniz

doReturn(null).doReturn(anotherInstance).when(mock).method();

şirin değil mi :)


4

MultipleAnswerHer çağrıda farklı cevaplar saplamamı sağlayan bir sınıf uyguladım . İşte kod parçası:

private final class MultipleAnswer<T> implements Answer<T> {

    private final ArrayList<Answer<T>> mAnswers;

    MultipleAnswer(Answer<T>... answer) {
        mAnswers = new ArrayList<>();
        mAnswers.addAll(Arrays.asList(answer));
    }

    @Override
    public T answer(InvocationOnMock invocation) throws Throwable {
        return mAnswers.remove(0).answer(invocation);
    }
}

1
Bu nesneyi kısa, basit ve okunabilir bir şekilde başlatabilir misiniz?
usr-local-ΕΨΗΕΛΩΝ

1

Aşağıda, farklı yöntem çağrılarında farklı bağımsız değişkenler döndürmek için ortak bir yöntem olarak kullanılabilir. Yapmamız gereken tek şey, her çağrıda nesnelerin alınacağı sırayla bir dizi geçirmemiz gerektiğidir.

@SafeVarargs
public static <Mock> Answer<Mock> getAnswerForSubsequentCalls(final Mock... mockArr) {
    return new Answer<Mock>() {
       private int count=0, size=mockArr.length;
       public Mock answer(InvocationOnMock invocation) throws throwable {
           Mock mock = null;
           for(; count<size && mock==null; count++){
                mock = mockArr[count];
           }

           return mock;    
       } 
    }
}

Ör. getAnswerForSubsequentCalls(mock1, mock3, mock2);ilk çağrıda mock1 nesnesini, ikinci çağrıda mock3 nesnesini ve üçüncü çağrıda mock2 nesnesini döndürecektir. Bu gibi kullanılmalıdır when(something()).doAnswer(getAnswerForSubsequentCalls(mock1, mock3, mock2)); .when(something()).thenReturn(mock1, mock3, mock2);


1

@ [Igor Nikolaev] 'in 8 yıl önceki cevabı ile ilgili Answerolarak , Java 8'de bulunan bir lambda ifadesi kullanılarak bir basitleştirilebilir .

when(someMock.someMethod()).thenAnswer(invocation -> {
    doStuff();
    return;
});

veya daha basit:

when(someMock.someMethod()).thenAnswer(invocation -> doStuff());

1

BDD tarzı:

import static org.mockito.BDDMockito.*;
...
    @Test
    void submit() {
        given(yourMock.yourMethod()).willReturn(1, 2, 3);

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.