Mockito - różnica między doReturn () a when ()

196

Obecnie używam Mockito do kpienia z obiektów warstwy usługi w aplikacji Spring MVC, w której chcę przetestować metody kontrolera. Jednak, kiedy czytałem o szczegółach Mockito, odkryłem, że metody doReturn(...).when(...)są równoważne when(...).thenReturn(...). Moje pytanie brzmi: po co są dwie metody, które robią to samo, czy jaka jest subtelna różnica między doReturn(...).when(...)i when(...).thenReturn(...)?

Każda pomoc będzie mile widziana.

czarna pantera
źródło
1
W javadoc jest kilka przypadków, w których doReturn()jest to przydatne.
Sotirios Delimanolis,
5
Myślę, że jedną z głównych różnic jest to, że doReturn (...). Gdy (..) jest starszy i nie jest tego typu bezpieczny i dlatego możemy go używać czasem, gdy kompilator ciągle narzeka na casting. Kiedy (..). To Powrót (..) jest znacznie lepszy pod względem bezpieczeństwa typu
user2511882

Odpowiedzi:

227

Obie składnie dla stubowania są w przybliżeniu równoważne. Jednak zawsze możesz użyć doReturn/whendo stubowania; ale są przypadki, w których nie można użyć when/thenReturn. Jednym z takich sposobów jest stubbingowanie pustek. Inne obejmują używanie szpiegów Mockito i wielokrotne stosowanie tej samej metody.

Jedną z rzeczy, która when/thenReturndaje ci to, czego doReturn/whennie ma, jest sprawdzanie typu zwracanej wartości w czasie kompilacji. Uważam jednak, że nie ma to prawie żadnej wartości - jeśli pomylisz się co do typu, przekonasz się, jak tylko uruchomisz test.

Zdecydowanie polecam tylko używać doReturn/when. Nie ma sensu uczyć się dwóch składni, kiedy to zrobisz.

Możesz odnieść się do mojej odpowiedzi z „Gramatyki” Forming Mockito - bardziej szczegółowej odpowiedzi na bardzo ściśle powiązane pytanie.

Dawood ibn Kareem
źródło
16
Nie zgadzam się z Davidem. Często spotykam się z sytuacjami, w których zwracam niewłaściwy typ podczas używania doReturn/wheni spędzam kilka minut zastanawiając się, co poszło nie tak. Sprawdzanie typu kompilacji staje się niezwykle przydatne w przypadku when/thenReturn.
Saket
11
Pamiętaj tylko, że Mockito zaleca używanie when/thenReturnzamiast doReturn/when.
CodyEngel
2
@CodyEngel i nie ma powodu do takiej rekomendacji, poza tym, co przedstawiłem w moich odpowiedziach tutaj i na stackoverflow.com/q/11462697 . Kilka lat temu rozmawiałem o tym z Brice Dutheilem, który obecnie jest głównym programistą Mockito, i, o ile dobrze pamiętam, zgadza się. Poproszę go o opublikowanie tutaj komentarza (nie ma gwarancji, że to zrobi).
Dawood ibn Kareem
18
W JavaDoc stwierdza, że doReturn/whenjest to kompromis. Zespół nie poleca w ten czy inny sposób, ale zauważa, że when/thenpodejście jest bardziej intuicyjne, bardziej czytelne i oferuje sprawdzanie czasu kompilacji, dzięki temu Mockito stało się popularne i łatwe w użyciu, nie zapominaj, że gdy baza kodu jest udostępniana przez różne umiejętności w zespole; ma jednak wady dotyczące szpiegów i metod pustki.
Brice
5
Dla przypomnienia : doReturn()ma tę wielką wadę, że zmienia się w kodowanie wywołań metod w stylu YODA. To, co później przychodzi, jest zapisywane jako pierwsze. Większość ludzi czyta od lewej do prawej; więc teraz musicie stale pamiętać o odwróceniu logiki powrotu w głowie.
GhostCat
199

Oba podejścia zachowują się inaczej, jeśli użyjesz szpiegowanego obiektu (z adnotacją @Spy) zamiast próbnego (z adnotacją @Mock):

  • when(...) thenReturn(...) wykonuje prawdziwe wywołanie metody tuż przed zwróceniem określonej wartości. Więc jeśli wywoływana metoda zgłosi wyjątek, musisz sobie z tym poradzić / wyśmiewać itp. Oczywiście nadal otrzymujesz swój wynik (to, co definiujesz thenReturn(...))

  • doReturn(...) when(...) w ogóle nie wywołuje tej metody .

Przykład:

public class MyClass {
     protected String methodToBeTested() {
           return anotherMethodInClass();
     }

     protected String anotherMethodInClass() {
          throw new NullPointerException();
     }
}

Test:

@Spy
private MyClass myClass;

// ...

// would work fine
doReturn("test").when(myClass).anotherMethodInClass();

// would throw a NullPointerException
when(myClass.anotherMethodInClass()).thenReturn("test");
akcasoy
źródło
37
To zachowanie działa tylko w przypadku obiektów szpiegujących, ponieważ są one „opakowaniami” rzeczywistych obiektów. W przypadku kpionych obiektów nie ma znaczenia, czy jest to kiedy / następnie Zwróć lub do Zwróć / kiedy. Wyśmiewane obiekty nigdy nie wywołują prawdziwych metod.
Rafael Orágio,
Czy możesz podać więcej informacji, dlaczego potrzebujemy tej funkcji? Nie widzę praktycznego przypadku użycia. Celem testu jest potwierdzenie poprawności kodu w różnych przypadkach użycia. Jeśli calll metody zgłasza wyjątek, powinien zgłosić wyjątek, a nie zwrócić wartości
Gleichmut
@Gleichmut To był hipotetyczny scenariusz, w którym pokazuję wykorzystanie / zaletę doReturn. W prawdziwej aplikacji metoda, która właśnie zwraca wyjątek, oczywiście nie ma sensu .. ale masz metody (prawdopodobnie nie tak cienkie jak ta), które mogą
generować
1
Tylko dla wyjaśnienia: metoda when (). ThenReturn () wywołuje rzeczywistą metodę (szpiega - nie ma znaczenia dla prób) tylko raz. Dzieje się tak w wierszu, w którym określasz zachowanie próbne (kiedy ( myClass.anotherMethodInClass () .thenRet ...). Następnie rzeczywista metoda nigdy nie jest wywoływana ponownie. Być może warto wiedzieć, czy spodziewałeś się jakiejś logiki dekoratora podczas czytania wyjaśnienia powyżej
Jonas
Nie wydaje się to zaletą doReturn(), wygląda na nadużycie biblioteki. Celem szpiegowania zamiast czystego kpienia jest wykorzystanie prawdziwych połączeń. Ostrzegają również przed używaniem Szpiegów w następujący sposób: github.com/mockito/mockito/wiki/Using-Spies-(and-Fakes) (i zalecają rozszerzenie klasy i zastąpienie metody zamiast tego)
Matthew Czytaj
13

Wydaje się, że Mockito javadoc mówi, dlaczego należy używać doReturn()zamiast when() Use doReturn () w tych rzadkich przypadkach, gdy nie można użyć Mockito.when (Object).

Uważaj, że Mockito.when (Object) jest zawsze zalecane do stubowania, ponieważ jest on bezpieczny dla typu argumentu i bardziej czytelny (szczególnie podczas stubowania kolejnych wywołań).

Oto te rzadkie sytuacje, w których przydatna jest funkcja doReturn ():

1. Szpiegowanie prawdziwych obiektów i wywoływanie prawdziwych metod w szpiegu przynosi efekty uboczne

List list = new LinkedList(); List spy = spy(list);

// Niemożliwe: wywoływana jest prawdziwa metoda, więc spy.get (0) zgłasza wyjątek IndexOutOfBoundsException (lista jest jeszcze pusta)

when(spy.get(0)).thenReturn("foo");

// Do stubowania musisz użyć doReturn (): doReturn("foo").when(spy).get(0);

2. Przesłanianie poprzedniego usuwania wyjątków:

when(mock.foo()).thenThrow(new RuntimeException());

// Niemożliwe: wywoływana jest wyjątkowa metoda foo (), dlatego zgłaszany jest wyjątek RuntimeException. when(mock.foo()).thenReturn("bar");

// Do stubowania musisz użyć doReturn ():

doReturn("bar").when(mock).foo(); Powyższe scenariusze pokazują kompromis eleganckiej składni Mockito. Pamiętaj jednak, że scenariusze są bardzo rzadkie. Szpiegowanie powinno być sporadyczne, a nadpisywanie wyjątków jest bardzo rzadkie. Nie wspominając o tym, że w ogólności nadpisywanie stubowania jest potencjalnym zapachem kodu, który wskazuje na zbyt wiele stubowania.


źródło
6

Kontynuując tę odpowiedź , istnieje jeszcze jedna różnica, że ​​jeśli chcesz, aby twoja metoda zwracała różne wartości, na przykład gdy jest wywoływana po raz pierwszy, wywoływana po raz drugi itd., Możesz przekazać wartości, na przykład ...

PowerMockito.doReturn(false, false, true).when(SomeClass.class, "SomeMethod", Matchers.any(SomeClass.class));

Więc zwróci false, gdy metoda zostanie wywołana w tym samym przypadku testowym, a następnie zwróci false ponownie i na koniec true.

AZ_
źródło