Korzystanie z ogólnej metody „any ()” Mockito

194

Mam interfejs z metodą, która oczekuje tablicy Foo:

public interface IBar {
  void doStuff(Foo[] arr);
}

Szydzę z tego interfejsu za pomocą Mockito i chciałbym to potwierdzić doStuff() jest on wywoływany, ale nie chcę sprawdzać poprawności przekazywanych argumentów - „nie przejmuj się”.

Jak napisać następujący kod za pomocą any()metody ogólnej zamiast anyObject()?

IBar bar = mock(IBar.class);
...
verify(bar).doStuff((Foo[]) anyObject());
ripper234
źródło

Odpowiedzi:

111

Od wersji Java 8 można używać metody bez argumentów any, a argument typu zostanie wyprowadzony przez kompilator:

verify(bar).doStuff(any());

Wyjaśnienie

Nowością w Javie 8 jest to, że docelowy typ wyrażenia będzie używany do wnioskowania o parametrach typu jego podwyrażeń. Przed Java 8 tylko argumenty metod były używane do wnioskowania o parametrach typu (przez większość czasu).

W takim przypadku typ parametru doStuffbędzie typem docelowym any(), a typ wartości zwracanej any()zostanie wybrany tak, aby pasował do tego typu argumentu.

Mechanizm ten został dodany w Javie 8 głównie w celu kompilacji wyrażeń lambda, ale ogólnie poprawia wnioskowania typu.


Typy pierwotne

To nie działa z typami pierwotnymi, niestety:

public interface IBar {
    void doPrimitiveStuff(int i);
}

verify(bar).doPrimitiveStuff(any()); // Compiles but throws NullPointerException
verify(bar).doPrimitiveStuff(anyInt()); // This is what you have to do instead

Problem polega na tym, że kompilator będzie wnioskować Integerjako wartość zwracana any(). Mockito nie będzie tego świadomy (z powodu kasowania typu) i zwróci domyślną wartość dla typów referencyjnych, tj null. Środowisko wykonawcze spróbuje rozpakować wartość zwracaną przez wywołanie intValuemetody przed przekazaniem jej doStuff, a wyjątek zostanie zgłoszony.

Lii
źródło
Jestem mile zaskoczony za każdym razem, gdy ta odpowiedź zyskuje aprobatę! Domyślam się, że pytanie to nie przyciągnie zbyt wiele uwagi od wersji Java 8, ponieważ anymetoda powinna po prostu działać. Nie szukasz odpowiedzi na rzeczy, które po prostu działają!
Lii
Przybyłem tu, ponieważ nie wiedziałem, dlaczego mój kod nie działa, any()ale było w porządku anyBoolean(), co pięknie pokazuje ostatnia część twojej odpowiedzi.
AdrienW
274

To powinno działać

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;

verify(bar).DoStuff(any(Foo[].class));
drganie
źródło
31
na wypadek, gdyby ktoś tego potrzebował w Scali:verify(bar).DoStuff(any[Array[Foo]])
Tolitius
6
Miałem problem z importem, w imporcie korzystałem z any () z hamcrest i kolidował on z tym z mockito.
Doppelganger,
4
Proszę spojrzeć na API, argument klasy służy tylko do rzutowania, metoda wciąż akceptuje dowolny obiekt! site.mockito.org/mockito/docs/current/org/mockito/… . W tym przypadku użyj isA () site.mockito.org/mockito/docs/current/org/mockito/… .
thilko
1
Ta klasa jest teraz przestarzała, aby uniknąć konfliktu nazw z Hamcrestem. Użyj org.mockito.ArgumentMatchers
leo9r
12

Możesz użyć Mockito.isA()do tego:

import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.verify;

verify(bar).doStuff(isA(Foo[].class));

http://site.mockito.org/mockito/docs/current/org/mockito/Matchers.html#isA(java.lang.Class)

thilko
źródło
To jest poprawna odpowiedź. Używanie dowolnego (Clazz) jest całkowicie błędne.
Surasin Tancharoen
3
@SurasinTancharoen Właściwie każdy (Class) jest tylko aliasem isA (Class) (patrz dokumentacja). Więc to wcale nie jest źle.
jmiserez,
8

Ponieważ musiałem korzystać z tej funkcji w moim najnowszym projekcie (w pewnym momencie zaktualizowaliśmy wersję 1.10.19), po to tylko, aby użytkownicy (którzy już używają wersji mockito-core 2.1.0 lub nowszej ) byli na bieżąco, statycznie metody z powyższych odpowiedzi należy pobrać z ArgumentMatchersklasy:

import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.ArgumentMatchers.any;

Pamiętaj o tym, jeśli planujesz aktualizować swoje artefakty Mockito, ponieważ prawdopodobnie począwszy od wersji 3, ta klasa może już nie istnieć:

Zgodnie z 2.1.0 i nowszymi Javadoc z org.mockito.Matchers stwierdza:

Zastosowanie org.mockito.ArgumentMatchers. Ta klasa jest teraz przestarzała, aby uniknąć konfliktu nazw z klasą Hamcrest * org.hamcrest.Matchers . Ta klasa prawdopodobnie zostanie usunięta w wersji 3.0.

Napisałem mały artykuł na temat symboli wieloznacznych mockito, jeśli jesteś gotowy na dalsze czytanie.

Maciej Kowalski
źródło
Jak mogę zaimportować org.mockito.ArgumentMatcher do Scali? Próbowałem zaimportować org.mockito.ArgumentMatcher.any Otrzymuję błąd `wartość any any not a member of object org.mockito.ArgumentMatcher
Manu Chadha
Czy możesz mi powiedzieć, jaki jest odpowiednik w wersji 3.0?
Manu Chadha
Dowiemy się, kiedy zostanie wydany;)
Maciej Kowalski