Farklı parametrelerle birden çok yöntem çağrısı nasıl doğrulanır


116

Davranışı doğrulamak istediğim aşağıdaki yönteme sahibim.

public void methodToTest(Exception e, ActionErrors errors) {
    ...

    errors.add("exception.message", 
            ActionMessageFactory.createErrorMessage(e.toString()));

    errors.add("exception.detail",
            ActionMessageFactory.createErrorMessage(e.getStackTrace()[0].toString()));

    ...
}

@Test sınıfımda bunun "istisna.message errors.add()" ve yine " istisna.detail " ile çağrıldığını doğrulamak için böyle bir şey yapmayı umuyordum.

verify(errors).add(eq("exception.message"), any(ActionError.class));
verify(errors).add(eq("exception.detail"), any(ActionError.class));

ancak Mockito aşağıdaki gibi şikayet ediyor

Argument(s) are different! Wanted:
actionErrors.add(
    "exception.message",
    <any>
);

Actual invocation has different arguments:
actionErrors.add(
    "exception.detail",
    org.apache.struts.action.ActionError@38063806
);

Mockito'ya her iki değeri de kontrol etmesini nasıl söyleyebilirim?


1
Farklı imzaya sahip 2 yönteminiz olduğunda, her ikisi için de ayrı test senaryosu yazabilirsiniz.
Naveen Babu

8
Evet, ancak bu durumda aynı yöntem imzası ancak yalnızca farklı bağımsız değişken değerleri
Brad

kullanmayı deneyebilirsinMockito.reset()
takacsot

Yanıtlar:


102

Daha fazla okuma beni ArgumentCaptors'ı ve aşağıdaki çalışmaları kullanmayı denemeye yönlendirdi, ancak istediğimden çok daha ayrıntılı.

ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);

verify(errors, atLeastOnce()).add(argument.capture(), any(ActionMessage.class));

List<String> values = argument.getAllValues();

assertTrue(values.contains("exception.message"));
assertTrue(values.contains("exception.detail"));

Bu yaklaşım kullanılarak belirli parametrelerin eşleştirildiğinden emin olmanın bir yolu var mı? Say örneğin OP'ın yöntem iki argüman vardı ve birlikte çağrıldı doğrulamak istedi
committedandroider

1
OP'nin test senaryosu methodToTest()tam olarak bir kez arar , bu nedenle bu cevap iki aramanın birlikte yapıldığını doğrular. List<String> valuesİddia edilen yakalanan sadece test edilen iki değeri içerecek ve diğerlerini içermeyecektir. Ayrıca ekleyebilirsiniz assertTrue(values.size == 2). Eğer istediğin buysa, 3 assertTrue ifadesini tek bir Hamcrest ile değiştirirdim ...assertThat(values, contains("exception.message", "exception.detail"));
Brad

OP'nin test durumu methodToTest () öğesini iki kez çağırmıyor mu?
committedandroider

üzgünüm net değildim. OP'nin iki argümanın birlikte çağrıldığını test etmek istediği senaryoya atıfta bulunuyordum. Dolayısıyla, yöntem imzası public void methodToTest (İstisna e, Mesaj m, ActionErrors hataları) gibi görünecektir, böylece belirli bir istisna belirli bir mesajla çağrılır. Ben sadece iki ArgumentCaptors ve daha sonra dizini almak ve her iki değer listelerinde bu endeksler de değerleri kullanarak karşılaştırabilirsiniz o sözde
committedandroider

OP'nin test vakası bir methodToTest()kez arar . Bu, ActionErrors errorsdahili olarak iki kez çağrılan yöntem bağımsız değişkenidir .
Brad

61

Her iki add()aramanın sırası alakalıysa, şunları kullanabilirsiniz InOrder:

InOrder inOrder = inOrder(errors);
inOrder.verify(errors).add(eq("exception.message"), any(ActionError.class));
inOrder.verify(errors).add(eq("exception.detail"), any(ActionError.class));

7
Tek bir errorsargümanı geçmek yeterlidir : InOrder inOrder = inOrder(errors);( belgelere bakın )
GreenhouseVeg

2
Ya sipariş ilgili DEĞİLSE? bu genellikle böyledir.
haelix

1
@haelix Bu durumda, Brads cevabını kullanın. Dönüştürme Listiçin Setgirdilerin Seti argümanı yakalamaları tarafından verilen set eşit olduğunu ve düşünmektedirler.
flopshot

25

Bunun gibi bir şey dene:

verify(errors, times(2))
     .add(AdditionalMatchers.or(eq("exception.message"), eq("exception.detail")),
          any(ActionError.class));

5
Çekiniz belli ki çok rahat.
haelix

17

muhtemelen kodunuzda bir probleminiz var. Çünkü aslında bu kodu yazıyorsunuz:

Map<Character, String> map = mock(Map.class);

map.put('a', "a");
map.put('b', "b");
map.put('c', "c");

verify(map).put(eq('c'), anyString());
verify(map).put(eq('a'), anyString());
verify(map).put(eq('b'), anyString());

İlk doğrulamanın, gerçek çağrılar açısından düzgün olmadığını unutmayın.

Ayrıca, sahip olmadığınız türlerle alay etmemenizi tavsiye ederim, örneğin payandalar türü.

[@Brad DÜZENLE]

Brice'in kodunu (yukarıda) IDE'mde çalıştırdıktan sonra ActionMessage yerine ActionError kullandığımı görebiliyorum, bu yüzden doğrulama () işlemim eşleşmiyordu. Başlangıçta gönderdiğim hata mesajı, eşleşmeyen ilk argüman olduğunu düşünerek beni yanılttı. İkinci argüman olduğu ortaya çıktı.

Yani sorumun cevabı

/** 
 * note that ActionMessageFactory.createErrorMessage() returns ActionMessage
 * and ActionError extends ActionMessage
 */
verify(errors).add(eq("exception.message"), any(ActionMessage.class));
verify(errors).add(eq("exception.detail"), any(ActionMessage.class));

1
Ne söylemeye çalıştığını anlamayın. Doğrulama sırası önemli mi? Doğrulama sırası önemliyse. O halde neden InOrder api sağlanıyor?
Oleksandr Papchenko

Tıpkı yukarıda yazılanlar gibi, doğrulama emrinin alakasız olması gibi; bu yüzden var InOrder.
Brice

12

Mockito.atLeastOnce()MockObject birçok kez çağrılacak olsa bile, Mockito'nun testi geçmesine izin veren bir seçeneği kullanabilirsiniz .

Mockito.verify(mockObject, Mockito.atLeastOnce()).testMethod(Mockito.eq(1));

Mockito.verify(mockObject, Mockito.atLeastOnce()).testMethod(Mockito.eq(2));

1

1) Mokito'ya toplam arama beklentisini söyleyin.

2) Mokito'ya her bir parametre kombinasyonunun kaç kez beklendiğini söyleyin.

verify(errors, times(2)).add(any(), any(ActionMessage.class));

verify(errors, atLeastOnce()).add(eq("exception.message"), any());
verify(errors, atLeastOnce()).add(eq("exception.detail"), any());

0

@ Sendon1928'e benzer şekilde şunları kullanabiliriz:

Mockito.times(wantedInvocationCount)

yöntemin kesin olarak adlandırıldığından emin olmak için (bence tercih edilen çözüm). Daha sonra arayabiliriz

Mockito.verifyNoMoreInteractions(mock)

Bu taklidin herhangi bir bağlamda kullanılmadığından emin olmak için. Tam örnek:

Mockito.verify(mockObject, Mockito.times(wantedInvocationCount)).testMethod(Mockito.eq(1));

Mockito.verify(mockObject, Mockito.times(wantedInvocationCount)).testMethod(Mockito.eq(2));

Mockito.verifyNoMoreInteractions(mockObject)
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.