mocking private static
Научете подигравателни частни, статични и Void методи в Mockito с примери:
В тази поредица от практически Уроци за Mockito , разгледахме различни видове Mockito Matchers в последния урок.
Най-общо казано, подигравките с частни и статични методи попадат в категорията на необичайното подиграване.
Ако възникне необходимост от подигравка на частни и статични методи / класове, това показва лошо реконструиран код и всъщност не е проверяем код и най-вероятно е някакъв наследствен код, който не е бил използван като много удобен за единичен тест.
Като каза това, все още съществува поддръжка за подиграване на частни и статични методи от няколко модулни тестови рамки като PowerMockito (а не директно от Mockito).
Подигравателните „void“ методи са често срещани, тъй като може да има методи, които по същество не връщат нищо, като актуализиране на ред на база данни (разглеждайте го като операция PUT на крайната точка на Rest API, която приема вход и не връща никакъв изход).
Mockito предоставя пълна поддръжка за подигравателни void методи, което ще видим с примери в тази статия.
c ++ въпроси за интервю и отговори за опитни
Какво ще научите:
- Powermock - кратко въведение
- Подигравка на частни методи
- Подигравателни статични методи
- Подигравателни методи за празнота
- Съвети и трикове
- Заключение
- Препоръчително четене
Powermock - Кратко въведение
За Mockito няма пряка поддръжка за подигравка на частни и статични методи. За да тествате частни методи, ще трябва рефакторирайте кода за да промените достъпа до защитен (или пакет) и ще трябва да избягвате статични / крайни методи.
По мое мнение Mockito умишлено не осигурява поддръжка за този вид подигравки, тъй като използването на тези видове кодови конструкции са кодови миризми и лошо проектиран код.
Но има рамки, които поддържат подигравки за частни и статични методи.
Powermock разширява възможностите на други рамки като EasyMock и Mockito и предоставя способността да се подиграва на статични и частни методи.
# 1) Как: Powermock прави това с помощта на персонализирана манипулация на байт кодове, за да поддържа подигравки на частни и статични методи, крайни класове, конструктори и т.н.
# 2) Поддържани пакети: Powermock предлага 2 API за разширение - един за Mockito и един за easyMock. Заради тази статия ще напишем примери с разширението Mockito за макет на мощност.
# 3) Синтаксис :Powermockito има почти подобен синтаксис като Mockito, с изключение на някои допълнителни методи за подигравка на статични и частни методи.
# 4) Настройка на Powermockito
За да включите библиотеката Mockito в проекти, базирани на gradle, по-долу са библиотеките, които трябва да бъдат включени:
testCompile group: 'org.powermock', name: 'powermock-api-mockito2', version: '1.7.4' testCompile group: 'org.powermock', name: 'powermock-module-junit4', version: '1.7.4'
Подобни зависимости са налични и за maven.
Powermock-api-mockito2 - Библиотеката трябва да включва разширения Mockito за Powermockito.
Powermock-module-junit4 - Модулът е необходим, за да включва PowerMockRunner (който е персонализиран бегач, който да се използва за провеждане на тестове с PowerMockito).
Тук е важно да се отбележи, че PowerMock не поддържа Junit5 test runner. Следователно тестовете трябва да бъдат написани срещу Junit4 и тестовете трябва да бъдат изпълнени с PowerMockRunner.
За да използвате PowerMockRunner - тестовият клас трябва да бъде отбелязан с @RunWith (PowerMockRunner.class)
Сега нека обсъдим, подигравайки подробно частни, статични и невалидни методи!
Подигравка на частни методи
Подигравките на частни методи, които се извикват вътре от тествания метод, могат да бъдат неизбежни в определени моменти. С помощта на powermockito това е възможно и проверката се извършва с помощта на нов метод, наречен ‘verifyPrivate’
Да вземем anПример където тестваният метод извиква частен метод (който връща булева стойност). За да заглуши този метод, за да върне true / false в зависимост от теста, трябва да се настрои мъниче за този клас.
За този пример тестваният клас се създава като шпионски екземпляр с подигравки върху няколко извиквания на интерфейс и извикване на частен метод.
Важни точки към Mock Private Method:
# 1) Тестовият метод или тестовият клас трябва да бъдат отбелязани с @ Подгответе се за тест (ClassUnderTest). Тази анотация казва на powerMockito да подготви определени класове за тестване.
Това ще бъдат предимно онези класове, които трябва да бъдат Манипулиран е байт код . Обикновено за крайни класове, класове, съдържащи частни и / или статични методи, които трябва да бъдат подигравани по време на тестване.
Пример:
@PrepareForTest(PriceCalculator.class)
# две) За да настроите мъниче на частен метод.
Синтаксис - когато (макет или шпионски екземпляр, “privateMethodName”). thenReturn (// връща стойност)
Пример:
when (priceCalculatorSpy, 'isCustomerAnonymous').thenReturn(false);
# 3) За да проверите забития частен метод.
Синтаксис - verifyPrivate (mockedInstance) .invoke (“privateMethodName”)
Пример:
verifyPrivate (priceCalculator).invoke('isCustomerAnonymous');
Пълна пробна проба: Продължавайки същия пример от предишните статии, където priceCalculator има някои подигравани зависимости като itemService, userService и т.н.
Създадохме нов метод, наречен - CalcuPriceWithPrivateMethod, който извиква частен метод в същия клас и връща дали клиентът е анонимен или не.
@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); }
Подигравателни статични методи
Статичните методи могат да се подиграват по подобен начин, както видяхме за частните методи.
Когато методът, който се тества, включва използването на статичен метод от същия клас (или от различен клас), ще трябва да включим този клас в анотацията PrepaForTest преди теста (или в тестовия клас).
Важни точки към макетните статични методи:
# 1) Тестовият метод или тестовият клас трябва да бъдат отбелязани с @ Подгответе се за тест (ClassUnderTest). Подобно на подигравките с частни методи / класове, това се изисква и за статични класове.
# две) Една допълнителна стъпка, която е необходима за статичните методи, е - mockStatic (// име на статичен клас)
Пример:
mockStatic(DiscountCategoryFinder.class)
# 3) За да настроите stub за статичен метод, е толкова добре, колкото забиване на който и да е метод на всеки друг макет на интерфейс / клас.
Например: За да заглушите getDiscountCategory () (който връща enum DiscountCategory със стойности PREMIUM & GENERAL) статичен метод от клас DiscountCategoryFinder, просто извадете, както следва:
when (DiscountCategoryFinder. getDiscountCategory ()).thenReturn(DiscountCategory. PREMIUM );
# 4) За да проверите фиктивната настройка на окончателния / статичен метод, може да се използва метод verifyStatic ().
Пример:
verifyStatic (DiscountCategoryFinder.class, times (1));
Подигравателни методи за празнота
Нека първо се опитаме да разберем какви видове случаи могат да включват зашеметяващи void методи:
# 1) Например извиквания на методи - които изпращат известие по имейл по време на процеса.
Например :Да предположим, че промените паролата си за вашата сметка за интернет банкиране, след като промяната е успешна, получавате известие по имейла си.
Това може да се разглежда като / changePassword като POST повикване към приложния програмен интерфейс (API) на банка, което включва извикване на void метод за изпращане на известие по имейл до клиента.
# две) Друг често срещан пример за извикване на метод void са актуализирани заявки към DB, които вземат някакъв вход и не връщат нищо.
Методите за забиване на void (т.е. методите, които не връщат нищо или извеждат изключение), могат да бъдат обработвани с помощта на doNothing (), doThrow () и doAnswer (), doCallRealMethod () функции . Той изисква да бъде настроен заглушителят, като се използват горепосочените методи според очакванията на теста.
Също така, имайте предвид, че всички извиквания на void метод по подразбиране се подиграват на doNothing (). Следователно, дори ако не е направена изрична фиктивна настройка ГРАНИЧНО извиква метод, поведението по подразбиране все още е doNothing ().
Нека да видим примери за всички тези функции:
За всички примери, нека приемем, че има клас StudentScoreUpdates който има метод calcuSumAndStore (). Този метод изчислява сумата от точки (като вход) и извиква a нищожен метод updateScores () на екземпляр на изпълнение на база данни.
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); } }
Ще пишем модулни тестове за извикване на метод на макет със следните примери:
# 1) doNothing () - doNothing () е поведението по подразбиране за извиквания на void метод в Mockito, т.е. дори ако проверите обаждане по void метод (без изрично да настроите void to doNothing (), проверката пак ще бъде успешна)
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()); }
Други употреби заедно с doNothing ()
да се) Когато методът void е извикан няколко пъти и искате да настроите различни отговори за различни извиквания, като - doNothing () за първото извикване и да хвърлите изключение за следващото извикване.
Например :Настройте макет по този начин:
Mockito. doNothing ().doThrow(new RuntimeException()).when(mockDatabase).updateScores( anyString (), anyInt ());
б) Когато искате да уловите аргументите, с които е извикан методът void, трябва да се използва функционалността ArgumentCaptor в Mockito. Това дава допълнителна проверка на аргументи, с които е извикан методът.
Пример с 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 ()- Това е полезно, когато просто искате да хвърлите изключение, когато методът void се извиква от тествания метод.
Например:
примери за клиентско сървърно приложение и уеб базирано приложение
Mockito.doThrow(newRuntimeException()).when(mockDatabase).updateScores ( anyString (), anyInt ());
# 3) doAnswer ()- doAnswer () просто предоставя интерфейс за извършване на някаква персонализирана логика.
E.g. Модифициране на някаква стойност чрез предадените аргументи, връщане на персонализирани стойности / данни, които нормален мъниче не би могъл да върне, особено за void методи.
За целите на демонстрацията - забих метода void на updateScores (), за да върна „ отговор() ”И отпечатайте стойността на един от аргументите, които трябваше да бъдат предадени, когато методът трябваше да бъде извикан.
Пример за код:
@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 ()- Частичните подигравки са подобни на заглушките (където можете да извикате реални методи за някои от методите, а останалите).
За void методи mockito предоставя специална функция, наречена doCallRealMethod (), която може да се използва, когато се опитвате да настроите макета. Това, което ще направи, е да извикаме метода real void с действителните аргументи.
Например:
Mockito. doCallRealMethod ().when(mockDatabaseImpl).updateScores( anyString (), anyInt ());
Съвети и трикове
# 1) Включване на множество статични класове в един и същ метод / клас на изпитване- Използване на PowerMockito ако има нужда да се подигравате с множество статични финални класове, тогава имената на класовете в @ Подгответе се за тест анотацията може да се спомене като стойност, разделена със запетая като масив (по същество приема масив от имената на класовете).
Пример:
@PrepareForTest({PriceCalculator.class, DiscountCategoryFinder.class})
Както е показано в примера по-горе, приемете, че PriceCalculator и DiscountCategoryFinder са окончателни класове, които трябва да се подиграват. И двете могат да бъдат споменати като масив от класове в анотацията PrepareForTest и могат да бъдат блокирани в тестовия метод.
# 2) Позициониране на атрибута PrepareForTest - Позиционирането на този атрибут е важно по отношение на вида тестове, които са включени в класа Test.
Ако всички тестове трябва да използват един и същ краен клас, тогава има смисъл да се спомене този атрибут на ниво тестов клас, което просто означава, че подготвеният клас ще бъде достъпен за всички тестови методи. За разлика от това, ако анотацията е спомената в тестовия метод, тя ще бъде достъпна само за конкретните тестове
Заключение
В този урок обсъдихме различни подходи за подиграване на статични, окончателни и невалидни методи.
Въпреки че използването на много статични или крайни методи пречи на проверяемостта и все пак има налична поддръжка за тестване / подигравка, за да се подпомогне създаването на единични тестове, за да се постигне по-голяма увереност в кода / приложението дори за наследения код, който обикновено не се използва за да бъдат проектирани за проверяемост.
За статични и крайни методи Mockito няма изчерпателна поддръжка, но библиотеки като PowerMockito (които наследяват много неща от Mockito) предоставят такава поддръжка и трябва действително да извършват манипулация на байт кода, за да поддържат тези функции.
Mockito out of the box поддържа зашеметяващи void методи и предоставя различни методи като doNothing, doAnswer, doThrow, doCallRealMethod и др. И може да се използва според изискванията на теста.
Най-често задаваните въпроси за интервю за Mockito са изложени накратко в следващия урок.
Препоръчително четене
- Mockito Tutorial: Mockito Framework for Mocking in Unit Testing
- Топ 12 въпроса за интервю за Mockito (подигравателно рамково интервю)
- Статично в C ++
- Java нишки с методи и жизнен цикъл
- Създаване на макети и шпиони в Mockito с примери за кодове
- Различни видове съвпадения, предоставени от Mockito
- Методи и техники за предотвратяване на дефекти
- Как да използваме методи в SoapUI за групово изпълнение на тестове - SoapUI Tutorial # 10