mocking private static
Naucz się wyszydzania metod prywatnych, statycznych i pustych w Mockito z przykładami:
W tej serii ćwiczeń praktycznych Poradniki na Mockito , przyjrzeliśmy się plikowi różne typy Mockito Matchers w ostatnim samouczku.
Ogólnie rzecz biorąc, kpiny z prywatnych i statycznych metod należą do kategorii niecodziennych kpot.
Jeśli zajdzie potrzeba mockowania prywatnych i statycznych metod / klas, oznacza to słabo refaktoryzowany kod i tak naprawdę nie jest kodem testowalnym i najprawdopodobniej jest to jakiś starszy kod, który nie był wcześniej przyjazny dla testów jednostkowych.
Powiedziawszy to, nadal istnieje wsparcie dla Mockowania prywatnych i statycznych metod przez kilka frameworków do testów jednostkowych, takich jak PowerMockito (a nie bezpośrednio przez Mockito).
Mockowanie metod „void” jest powszechne, ponieważ mogą istnieć metody, które zasadniczo niczego nie zwracają, na przykład aktualizowanie wiersza bazy danych (traktuj to jako operację PUT punktu końcowego interfejsu API Rest, która akceptuje dane wejściowe i nie zwraca żadnych danych wyjściowych).
Mockito zapewnia pełną obsługę mockowania metod void, które zobaczymy na przykładach w tym artykule.
jak używać wyrażeń regularnych w C ++
Czego się nauczysz:
- Powermock - krótkie wprowadzenie
- Kpiny z metod prywatnych
- Mockowanie metod statycznych
- Metody kpiny z pustki
- Porady & Triki
- Wniosek
- rekomendowane lektury
Powermock - Krótkie wprowadzenie
W przypadku Mockito nie ma bezpośredniego wsparcia dla mockowania metod prywatnych i statycznych. Aby przetestować metody prywatne, będziesz musiał refaktoryzacja kodu aby zmienić dostęp do chronionego (lub pakietu) i będziesz musiał unikać metod statycznych / ostatecznych.
Moim zdaniem Mockito celowo nie zapewnia wsparcia dla tego typu makiet, ponieważ używanie tego rodzaju konstrukcji kodu to zapachy kodu i źle zaprojektowany kod.
Istnieją jednak struktury, które obsługują mockowanie metod prywatnych i statycznych.
Powermock rozszerza możliwości innych frameworków, takich jak EasyMock i Mockito oraz zapewnia możliwość mockowania metod statycznych i prywatnych.
# 1) Jak: Powermock robi to za pomocą niestandardowej manipulacji kodem bajtowym, aby wspierać mockowanie metod prywatnych i statycznych, klas końcowych, konstruktorów i tak dalej.
# 2) Obsługiwane pakiety: Powermock zapewnia 2 rozszerzenia API - jeden dla Mockito i jeden dla easyMock. Na potrzeby tego artykułu napiszemy przykłady z rozszerzeniem Mockito do Power Mock.
# 3) Składnia :Powermockito ma prawie podobną składnię jak Mockito, z wyjątkiem kilku dodatkowych metod naśladowania metod statycznych i prywatnych.
# 4) Konfiguracja Powermockito
Aby uwzględnić bibliotekę Mockito w projektach opartych na gradle, poniżej znajdują się biblioteki, które należy uwzględnić:
testCompile group: 'org.powermock', name: 'powermock-api-mockito2', version: '1.7.4' testCompile group: 'org.powermock', name: 'powermock-module-junit4', version: '1.7.4'
Podobne zależności są również dostępne dla mavena.
Powermock-api-mockito2 - Biblioteka musi zawierać rozszerzenia Mockito dla Powermockito.
Moduł Powermock-junit4 - Moduł musi zawierać PowerMockRunner (który jest niestandardowym runner'em do uruchamiania testów z PowerMockito).
Ważną kwestią, na którą należy tutaj zwrócić uwagę, jest to, że PowerMock nie obsługuje uruchamiania testowego Junit5. Dlatego testy muszą być napisane dla Junit4, a testy muszą być wykonane za pomocą PowerMockRunner.
Aby użyć PowerMockRunner - klasa testowa musi być opatrzona adnotacją @RunWith (PowerMockRunner.class)
Omówmy teraz szczegółowo metody prywatne, statyczne i puste!
Kpiny z metod prywatnych
Mockowanie metod prywatnych, które są wywoływane wewnętrznie z testowanej metody, może być czasami nieuniknione. Korzystając z powermockito, jest to możliwe, a weryfikacja odbywa się przy użyciu nowej metody o nazwie „verifyPrivate”
Weźmy naPrzykład gdzie testowana metoda wywołuje metodę prywatną (która zwraca wartość logiczną). Aby ta metoda zwróciła wartość prawda / fałsz w zależności od testu, należy ustawić kod pośredniczący w tej klasie.
W tym przykładzie testowana klasa jest tworzona jako instancja szpiegowska z mockingiem przy kilku wywołaniach interfejsu i wywołaniu metody prywatnej.
Ważne punkty dotyczące Mock Private Method:
# 1) Metoda testowa lub klasa testowa muszą być opatrzone adnotacją @ PrepareForTest (ClassUnderTest). Ta adnotacja nakazuje powerMockito przygotować określone klasy do testów.
Będą to głównie te zajęcia, które muszą być Zmieniono kod bajtowy . Zwykle w przypadku klas końcowych są to klasy zawierające metody prywatne i / lub statyczne, które muszą być mockowane podczas testowania.
Przykład:
@PrepareForTest(PriceCalculator.class)
#dwa) Aby skonfigurować kod pośredniczący przy użyciu metody prywatnej.
Składnia - when (fałszywa lub szpiegowska instancja, „privateMethodName”). thenReturn (// zwracana wartość)
Przykład:
when (priceCalculatorSpy, 'isCustomerAnonymous').thenReturn(false);
# 3) Aby zweryfikować skróconą metodę prywatną.
Składnia - verifyPrivate (mockedInstance) .invoke („privateMethodName”)
Przykład:
verifyPrivate (priceCalculator).invoke('isCustomerAnonymous');
Kompletna próbka testowa: Kontynuując ten sam przykład z poprzednich artykułów, w których priceCalculator ma pewne mockowane zależności, takie jak itemService, userService itp.
Stworzyliśmy nową metodę o nazwie - calculatorPriceWithPrivateMethod, która wywołuje metodę prywatną wewnątrz tej samej klasy i zwraca, czy klient jest anonimowy, czy nie.
@Test @PrepareForTest(PriceCalculator.class) public void calculatePriceForAnonymous_witStubbedPrivateMethod_returnsCorrectPrice() throws Exception { // Arrange ItemSku item1 = new ItemSku(); item1.setApplicableDiscount(5.00); item1.setPrice(100.00); double expectedPrice = 90.00; // Setting up stubbed responses using mocks when(priceCalculatorSpy, 'isCustomerAnonymous').thenReturn(false); when(mockedItemService.getItemDetails(123)).thenReturn(item1); // Act double actualDiscountedPrice = priceCalculatorSpy.calculatePriceWithPrivateMethod(123); // Assert verifyPrivate(priceCalculator).invoke('isCustomerAnonymous'); assertEquals(expectedPrice, actualDiscountedPrice); }
Mockowanie metod statycznych
Metody statyczne można wyszydzać w podobny sposób, jak widzieliśmy w przypadku metod prywatnych.
Gdy testowana metoda wymaga użycia metody statycznej z tej samej klasy (lub z innej klasy), będziemy musieli uwzględnić tę klasę w adnotacji readyForTest przed testem (lub w klasie testowej).
Ważne punkty dotyczące pozorowanych metod statycznych:
# 1) Metoda testowa lub klasa testowa muszą być opatrzone adnotacją @ PrepareForTest (ClassUnderTest). Podobnie jak w przypadku mockowania prywatnych metod / klas, jest to wymagane również w przypadku klas statycznych.
#dwa) Dodatkowym krokiem wymaganym w przypadku metod statycznych jest - mockStatic (// nazwa klasy statycznej)
najlepsze oprogramowanie do kompresji plików wideo
Przykład:
mockStatic(DiscountCategoryFinder.class)
# 3) Skonfigurowanie kodu pośredniczącego w metodzie statycznej jest tak samo dobre, jak utworzenie kodu pośredniczącego dowolnej metody w innych instancjach makiet interfejsu / klasy.
Na przykład: Aby odgiąć metodę getDiscountCategory () (która zwraca wyliczenie DiscountCategory z wartościami PREMIUM i GENERAL) statycznej metody klasy DiscountCategoryFinder, wystarczy odgiąć w następujący sposób:
when (DiscountCategoryFinder. getDiscountCategory ()).thenReturn(DiscountCategory. PREMIUM );
# 4) Aby zweryfikować próbną konfigurację w metodzie końcowej / statycznej, można użyć metody verifyStatic ().
Przykład:
verifyStatic (DiscountCategoryFinder.class, times (1));
Metody kpiny z pustki
Najpierw spróbujmy zrozumieć, jakiego rodzaju przypadki użycia mogą obejmować metody usuwania void:
# 1) Na przykład wywołuje metodę - która wysyła powiadomienie e-mail w trakcie procesu.
Na przykład :Załóżmy, że zmieniasz hasło do swojego konta bankowości internetowej, a gdy zmiana się powiedzie, otrzymasz powiadomienie e-mailem.
Można to traktować jako / changePassword jako wywołanie POST do interfejsu API banku, które obejmuje wywołanie metody void w celu wysłania powiadomienia e-mail do klienta.
#dwa) Innym typowym przykładem wywołania metody void są zaktualizowane żądania do bazy danych, które pobierają dane wejściowe i nic nie zwracają.
Stubbing void methods (tj. Metody, które nic nie zwracają lub zgłaszają wyjątek), można obsłużyć za pomocą Funkcje doNothing (), doThrow () i doAnswer (), doCallRealMethod () . Wymaga skonfigurowania kodu pośredniczącego przy użyciu powyższych metod zgodnie z oczekiwaniami testowymi.
Należy również zauważyć, że wszystkie wywołania metody void są domyślnie wyszywane przez metodę doNothing (). W związku z tym, nawet jeśli nie jest wykonywana jawna próbna konfiguracja UNIEWAŻNIĆ wywołania metody, domyślnym zachowaniem jest nadal doNothing ().
Zobaczmy przykłady wszystkich tych funkcji:
Dla wszystkich przykładów załóżmy, że istnieje klasa StudentScoreUpdates który ma metodę obliczSumAndStore (). Ta metoda oblicza sumę wyników (jako dane wejściowe) i wywołuje plik unieważnić metoda updateScores () w instancji databaseImplementation.
public class StudentScoreUpdates { public IDatabase databaseImpl; public StudentScoreUpdates(IDatabase databaseImpl) { this.databaseImpl = databaseImpl; } public void calculateSumAndStore(String studentId, int() scores) { int total = 0; for(int score : scores) { total = total + score; } // write total to DB databaseImpl.updateScores(studentId, total); } }
Będziemy pisać testy jednostkowe dla wywołania metody mock z poniższymi przykładami:
# 1) doNothing () - doNothing () jest domyślnym zachowaniem dla wywołań metod void w Mockito, tj. Nawet jeśli zweryfikujesz wywołanie metody void (bez jawnego ustawienia void do doNothing (), weryfikacja nadal zakończy się powodzeniem)
public void calculateSumAndStore_withValidInput_shouldCalculateAndUpdateResultInDb() { // Arrange studentScores = new StudentScoreUpdates(mockDatabase); int() scores = {60,70,90}; Mockito.doNothing().when(mockDatabase).updateScores(anyString(), anyInt()); // Act studentScores.calculateSumAndStore('student1', scores); // Assert Mockito.verify(mockDatabase, Mockito.times(1)).updateScores(anyString(), anyInt()); }
Inne zastosowania wraz z doNothing ()
do) Gdy metoda void jest wywoływana wiele razy i chcesz skonfigurować różne odpowiedzi dla różnych wywołań, na przykład - doNothing () dla pierwszego wywołania i zgłosić wyjątek przy następnym wywołaniu.
Na przykład :Skonfiguruj makietę w ten sposób:
Mockito. doNothing ().doThrow(new RuntimeException()).when(mockDatabase).updateScores( anyString (), anyInt ());
b) Jeśli chcesz przechwycić argumenty, z którymi została wywołana metoda void, należy użyć funkcji ArgumentCaptor w Mockito. Daje to dodatkową weryfikację argumentów, z którymi metoda została wywołana.
Przykład z ArgumentCaptor:
public void calculateSumAndStore_withValidInput_shouldCalculateAndUpdateResultInDb() { // Arrange studentScores = new StudentScoreUpdates(mockDatabase); int() scores = {60,70,90}; Mockito.doNothing().when(mockDatabase).updateScores(anyString(), anyInt()); ArgumentCaptor studentIdArgument = ArgumentCaptor.forClass(String.class); // Act studentScores.calculateSumAndStore('Student1', scores); // Assert Mockito.verify(mockDatabase, Mockito.times(1)).updateScores(studentIdArgument.capture(), anyInt()); assertEquals('Student1', studentIdArgument.getValue()); }
# 2) doThrow ()- Jest to przydatne, gdy chcesz po prostu zgłosić wyjątek, gdy metoda void jest wywoływana z testowanej metody.
Na przykład:
Mockito.doThrow(newRuntimeException()).when(mockDatabase).updateScores ( anyString (), anyInt ());
# 3) doAnswer ()- doAnswer () po prostu zapewnia interfejs do wykonywania niestandardowej logiki.
Na przykład. Modyfikowanie niektórych wartości za pomocą przekazanych argumentów, zwracanie niestandardowych wartości / danych, których normalny kod pośredniczący nie mógłby zwrócić, szczególnie w przypadku metod void.
Dla celów demonstracyjnych - zablokowałem metodę void updateScores (), aby zwracała „ odpowiedź() ”I wypisuje wartość jednego z argumentów, który powinien był zostać przekazany, gdy należało wywołać metodę.
Przykład kodu:
@Test public void calculateSumAndStore_withValidInput_shouldCalculateAndUpdateResultInDb() { // Arrange studentScores = new StudentScoreUpdates(mockDatabaseImpl); int() scores = {60,70,90}; Mockito.doCallRealMethod().when(mockDatabaseImpl).updateScores(anyString(), anyInt()); doAnswer(invocation -> { Object() args = invocation.getArguments(); Object mock = invocation.getMock(); System.out.println(args(0)); return mock; }).when(mockDatabaseImpl).updateScores(anyString(), anyInt()); // Act studentScores.calculateSumAndStore('Student1', scores); // Assert Mockito.verify(mockDatabaseImpl, Mockito.times(1)).updateScores(anyString(), anyInt()); }
# 4) doCallRealMethod ()- Częściowe makiety są podobne do stubów (gdzie możesz wywołać prawdziwe metody dla niektórych metod i odrzucić resztę).
W przypadku metod void mockito udostępnia specjalną funkcję o nazwie doCallRealMethod (), której można użyć, gdy próbujesz ustawić makietę. To, co zrobi, to wywołanie prawdziwej metody void z rzeczywistymi argumentami.
Na przykład:
Mockito. doCallRealMethod ().when(mockDatabaseImpl).updateScores( anyString (), anyInt ());
Porady & Triki
# 1) Włączanie wielu statycznych klas do tej samej metody / klasy testowej- Korzystanie z PowerMockito jeśli istnieje potrzeba Mock wielu klas Static of Final, nazwy klas w @ PrepareForTest adnotacja może być wymieniona jako wartość oddzielona przecinkami jako tablica (zasadniczo akceptuje tablicę nazw klas).
Przykład:
@PrepareForTest({PriceCalculator.class, DiscountCategoryFinder.class})
Jak pokazano w powyższym przykładzie, załóżmy, że zarówno PriceCalculator, jak i DiscountCategoryFinder są klasami końcowymi, które należy wyszydzać. Obydwa można wymienić jako tablicę klas w adnotacji PrepareForTest i można je umieścić w metodzie testowej.
# 2) Pozycjonowanie atrybutu PrepareForTest - Pozycja tego atrybutu jest ważna ze względu na rodzaj testów, które są zawarte w klasie Test.
Jeśli wszystkie testy muszą korzystać z tej samej klasy końcowej, warto wspomnieć o tym atrybucie na poziomie klasy testów, co po prostu oznacza, że przygotowana klasa będzie dostępna dla wszystkich Metod Testowych. W przeciwieństwie do tego, jeśli adnotacja jest wspomniana w metodzie testowej, będzie dostępna tylko dla tego konkretnego testu
Wniosek
W tym samouczku omówiliśmy różne podejścia do mockowania metod statycznych, końcowych i void.
Chociaż użycie wielu statycznych lub końcowych metod utrudnia testowanie, nadal istnieje wsparcie dla testowania / mockowania, aby pomóc w tworzeniu testów jednostkowych w celu uzyskania większego zaufania do kodu / aplikacji, nawet w przypadku starszego kodu, który zwykle nie jest używany do być zaprojektowane pod kątem testowalności.
W przypadku metod statycznych i końcowych Mockito nie ma standardowej obsługi, ale biblioteki takie jak PowerMockito (które dziedziczą wiele rzeczy z Mockito) zapewniają takie wsparcie i muszą faktycznie wykonywać manipulację kodem bajtowym, aby obsługiwać te funkcje.
Mockito po wyjęciu z pudełka obsługuje metody stubbing void i zapewnia różne metody, takie jak doNothing, doAnswer, doThrow, doCallRealMethod itp. I może być używane zgodnie z wymaganiami testu.
Najczęściej zadawane pytania do wywiadu Mockito są omówione w naszym następnym samouczku.
POPRZEDNIA samouczek | NEXT Tutorial
rekomendowane lektury
- Samouczek Mockito: Mockito Framework do mockowania w testach jednostkowych
- 12 najpopularniejszych pytań do wywiadu Mockito (wywiady z mocking Framework)
- Statyczny w C ++
- Wątki Java z metodami i cyklem życia
- Tworzenie mocków i szpiegów w Mockito z przykładami kodu
- Różne typy dopasowań zapewniane przez Mockito
- Metody i techniki zapobiegania defektom
- Jak używać metod w SoapUI do masowego wykonywania testów - SoapUI samouczek nr 10