Mockito, birden çok kez çağrılan bir yöntemin argümanlarını yakalayabilir mi?


446

İki kez çağrılan bir yöntem var ve ikinci yöntem çağrısının argümanını yakalamak istiyorum.

İşte denedim:

ArgumentCaptor<Foo> firstFooCaptor = ArgumentCaptor.forClass(Foo.class);
ArgumentCaptor<Foo> secondFooCaptor = ArgumentCaptor.forClass(Foo.class);
verify(mockBar).doSomething(firstFooCaptor.capture());
verify(mockBar).doSomething(secondFooCaptor.capture());
// then do some assertions on secondFooCaptor.getValue()

Ama TooManyActualInvocationsMockito'nun düşündüğü gibi bir İstisna alıyorumdoSomething sadece bir kez çağrılması gerektiğini .

İkinci çağrısının argümanını nasıl doğrulayabilirim doSomething?

Yanıtlar:


784

Bence olmalı

verify(mockBar, times(2)).doSomething(...)

Mockito javadoc'tan örnek :

ArgumentCaptor<Person> peopleCaptor = ArgumentCaptor.forClass(Person.class);
verify(mock, times(2)).doSomething(peopleCaptor.capture());

List<Person> capturedPeople = peopleCaptor.getAllValues();
assertEquals("John", capturedPeople.get(0).getName());
assertEquals("Jane", capturedPeople.get(1).getName());

3
doSomething()Bununla ilgili her ayrı çağrıda aktarılan argümanları yakalayabilir misiniz ?
— matt b

36
Böyle bir şey yapmanız durumunda: Person person = new Person("John"); doSomething(person); person.setName("Jane"); doSomething(person);yakalanan argümanın iki kez aynı olacağı belirtilmelidir (çünkü aslında aynı kişi nesnesidir), bu yüzden capturedPeople.get(0).getName() == capturedPeople.get(1).getName() == "Jane"ayrıca groups.google.com/forum/#!msg/mockito/ adresine bakın. KBRocVedYT0 / 5HtARMl9r2wJ .
— asmaier

2
Bu güzel, ama iki farklı tipte nesne çağrısını nasıl test edebilirim? Örneğin ExecutorService.submit (yeni MyRunableImpl ()); ve sonra ExecutorService.submit (yeni MyAnotherRunableImpl ())?
— Leon

Bir kişinin @asmaier tarafından açıklanan davayı ele alması gerekiyorsa, burada bir cevap gönderdim: stackoverflow.com/a/36574817/1466267
— SpaceTrucker

1
Leon'un sorusunun cevabını hala merak eden herkes için ortak taban sınıfını ( Runnable) kullanır ve gerekirse yakalanan argümanda daha spesifik bir tür kontrolü yaparsınız.
— Matthew

50

Mockito 2.0'dan bu yana, Matchers.argThat (ArgumentMatcher) statik yöntemini kullanma olasılığı da vardır . Java 8'in yardımıyla artık yazmak daha temiz ve daha okunaklı:

verify(mockBar).doSth(argThat((arg) -> arg.getSurname().equals("OneSurname")));
verify(mockBar).doSth(argThat((arg) -> arg.getSurname().equals("AnotherSurname")));

Daha düşük Java sürümüne bağlıysanız, o kadar da kötü değil:

verify(mockBar).doSth(argThat(new ArgumentMatcher<Employee>() {
        @Override
        public boolean matches(Object emp) {
            return ((Employee) emp).getSurname().equals("SomeSurname");
        }
    }));

Elbette bunların hiçbiri InOrder'ı kullanmanız gereken arama sırasını doğrulayamaz :

InOrder inOrder = inOrder(mockBar);

inOrder.verify(mockBar).doSth(argThat((arg) -> arg.getSurname().equals("FirstSurname")));
inOrder.verify(mockBar).doSth(argThat((arg) -> arg.getSurname().equals("SecondSurname")));

Lütfen aşağıdaki gibi arama yapmayı mümkün kılan mockito-java8 projesine göz atın :

verify(mockBar).doSth(assertArg(arg -> assertThat(arg.getSurname()).isEqualTo("Surname")));

2
Bu güzel bir teknik. Şu anda bazı oldukça şifreli çıktılar alıyorum: "Aranıyor ama çağrılmadı: / n mockAppender.append (<Dizin yöneticisi ut $$ lambda $ 5 9/1 3 1 9 5 1 0 1 6>);" - arg bir var CharSequence. Raporun "aranıyor" argümanını düzgün şekilde yazdırmasını sağlamanın herhangi bir yolunu biliyor musunuz?
— mike rodent

@mikerodent ArgumentMatcher <T> uygulayan bir sınıf oluşturmanın daha ayrıntılı yoluna giderseniz şifreli çıktı düzeltilebilir. Uygulamanızda toString yönteminin geçersiz kılınması, mockito test çıktısında istediğiniz iletileri sağlayacaktır.
— Noah Solomon

25

doSomething()Sadece sonuncusu için yapılan tüm aramaları doğrulamak istemiyorsanız kullanabilirsiniz ArgumentCaptor.getValue(). Mockito javadoc'a göre :

Yöntem birden çok kez çağrıldıysa, yakalanan en son değeri döndürür

Yani bu işe yarayacaktır ( Foobir yöntemi olduğunu varsayar getName()):

ArgumentCaptor<Foo> fooCaptor = ArgumentCaptor.forClass(Foo.class);
verify(mockBar, times(2)).doSomething(fooCaptor.capture());
//getValue() contains value set in second call to doSomething()
assertEquals("2nd one", fooCaptor.getValue().getName());

her iki değeri de yakalamanın bir yolu var mı?
— Hars

9

@Captor açıklamalı ArgumentCaptor öğesini de kullanabilirsiniz. Örneğin:

@Mock
List<String> mockedList;

@Captor
ArgumentCaptor<String> argCaptor;

@BeforeTest
public void init() {
    //Initialize objects annotated with @Mock, @Captor and @Spy.
    MockitoAnnotations.initMocks(this);
}

@Test
public void shouldCallAddMethodTwice() {
    mockedList.add("one");
    mockedList.add("two");
    Mockito.verify(mockedList, times(2)).add(argCaptor.capture());

    assertEquals("one", argCaptor.getAllValues().get(0));
    assertEquals("two", argCaptor.getAllValues().get(1));
}

6

Java 8'in lambdasları ile,

org.mockito.invocation.InvocationOnMock

when(client.deleteByQuery(anyString(), anyString())).then(invocationOnMock -> {
    assertEquals("myCollection", invocationOnMock.getArgument(0));
    assertThat(invocationOnMock.getArgument(1), Matchers.startsWith("id:"));
}

Bunun eski yöntemden nasıl daha uygun olduğunu göremiyorum. Lambdaların iyi kullanımını seviyorum, ama bunun bir olup olmadığından emin değilim.
— Eric Wilson

0

Her şeyden önce: her zaman mockito static'i içe aktarmalısınız, bu şekilde kod çok daha okunabilir (ve sezgisel) olacaktır - aşağıdaki kod örnekleri çalışmasını gerektirir:

import static org.mockito.Mockito.*;

Verify () yönteminde, testte yürütmeyi sağlamak için ArgumentCaptor ve argümanları değerlendirmek için ArgumentCaptor iletebilirsiniz:

ArgumentCaptor<MyExampleClass> argument = ArgumentCaptor.forClass(MyExampleClass.class);
verify(yourmock, atleast(2)).myMethod(argument.capture());

List<MyExampleClass> passedArguments = argument.getAllValues();

for (MyExampleClass data : passedArguments){
    //assertSometing ...
    System.out.println(data.getFoo());
}

Testiniz sırasında iletilen tüm bağımsız değişkenlerin listesine argument.getAllValues ​​() yöntemi aracılığıyla erişilebilir.

Tek (son çağrılan) bağımsız değişkenin değerine, daha fazla manipülasyon / kontrol veya ne yapmak isterseniz yapmak için argument.getValue () aracılığıyla erişilebilir.

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.