JMockit 101

1. Въведение

С тази статия ще стартираме нова серия, центрирана около подигравателния набор от инструменти JMockit.

В тази първа част ще говорим за това какво е JMockit, неговите характеристики и как се създават и използват макети с него.

По-късните статии ще се съсредоточат върху неговите възможности.

2. JMockit

2.1. Въведение

Първо, нека поговорим за това какво е JMockit: Java рамка за подигравки на обекти в тестове (можете да го използвате както за JUnit, така и за TestNG).

Той използва приложни програмни интерфейси (API) на Java, за да модифицира байт кода на класовете по време на изпълнение, за да промени динамично тяхното поведение. Някои от силните му страни са неговата изразимост и нестандартната му способност да се подиграват на статични и частни методи.

Може би сте нов за JMockit, но определено не се дължи на това, че е нов. Разработването на JMockit стартира през юни 2006 г. и първото му стабилно издание датира до декември 2012 г., така че съществува от известно време (текущата версия е 1.24 към момента на писане на статията).

2.2. Зависимост на Maven

Първо, ще трябва да добавим jmockit зависимостта към нашия проект:

 org.jmockit jmockit 1.41 

2.3. Изразливостта на JMockit

Както беше казано по-рано, една от най-силните страни на JMockit е неговата изразимост. За да създадете подигравки и да дефинирате тяхното поведение, вместо да извиквате методи от подигравателния API, просто трябва да ги дефинирате директно.

Това означава, че няма да правите неща като:

API.expect(mockInstance.method()).andThenReturn(value).times(2);

Вместо това очаквайте неща като:

new Expectation() { mockInstance.method(); result = value; times = 2; }

Може да изглежда, че това е повече код, но можете просто да поставите и трите реда само на един. Наистина важната част е, че не се окажете с голям „влак“ от верижни извиквания на методи. Вместо това получавате дефиниция за това как искате да се държи макетът, когато бъде извикан.

Ако вземете предвид, че в частта result = value можете да върнете каквото и да е (фиксирани стойности, динамично генерирани стойности, изключения и т.н.), изразителността на JMockit става още по-очевидна.

2.4. Моделът за запис, повторение и проверка

Тестовете, използващи JMockit, са разделени на три диференцирани етапа: запис, повторение и проверка.

  1. Във фазата на запис , по време на подготовката на теста и преди извикванията към методите, които искаме да бъдат изпълнени, ще дефинираме очакваното поведение за всички тестове, които да бъдат използвани през следващия етап.
  2. В преиграване фаза е тази, в която се изпълнява кода, който се изпитва. Извикванията на подигравани методи / конструктори, записани преди това на предишния етап, сега ще бъдат повторени.
  3. И накрая, във фазата на проверка ще твърдим, че резултатът от теста е този, който сме очаквали (и че макетите са се държали и са били използвани според дефинираното във фазата на запис).

С пример за код, каркас за тест би изглеждал по следния начин:

@Test public void testWireframe() { // preparation code not specific to JMockit, if any new Expectations() {{ // define expected behaviour for mocks }}; // execute code-under-test new Verifications() {{ // verify mocks }}; // assertions }

3. Създаване на подигравки

3.1. Анотации на JMockit

Когато използвате JMockit, най-лесният начин да използвате макети е да използвате анотации. Има три за създаване на макети ( @Mocked , @Injectable и @Capturing ) и един за определяне на тествания клас ( @Tested ).

Когато използвате анотацията @Mocked в поле, тя ще създаде подигравани екземпляри на всеки нов обект от конкретния клас.

От друга страна, с @Injectable анотацията ще бъде създаден само един подиграван екземпляр.

Последната анотация @Capturing ще се държи като @Mocked, но ще разшири обхвата си до всеки подклас, разширяващ или прилагащ типа на анотираното поле.

3.2. Предаване на аргументи на тестове

При използване на JMockit е възможно предаването на макети като тестови параметри. Това е доста полезно за създаване на макет само за конкретния тест, като например сложен обект на модел, който се нуждае от специфично поведение само за един тест например. Би било нещо подобно:

@RunWith(JMockit.class) public class TestPassingArguments { @Injectable private Foo mockForEveryTest; @Tested private Bar bar; @Test public void testExample(@Mocked Xyz mockForJustThisTest) { new Expectations() {{ mockForEveryTest.someMethod("foo"); mockForJustThisTest.someOtherMethod(); }}; bar.codeUnderTest(); } }

Този начин за създаване на макет, като се предава като параметър, вместо да се налага да извикваме някакъв API метод, отново ни показва изразимостта, за която говорим от самото начало.

3.3. Пълен пример

За да завършим тази статия, ще включим пълен пример за тест, използващ JMockit.

В този пример ще тестваме клас Performer, който използва Collaborator в метода си perfor () . Това извършване () метод, получава Модел обект като параметър, от който ще използва своето getInfo () , която връща низ, това String ще бъдат прехвърлени към Сътрудничество () метода от сътрудник , че ще се върне вярно за този конкретен тест, и тази стойност ще бъде предадена на метода receive () от Collaborator .

И така, тестваните класове ще изглеждат така:

public class Model { public String getInfo(){ return "info"; } } public class Collaborator { public boolean collaborate(String string){ return false; } public void receive(boolean bool){ // NOOP } } public class Performer { private Collaborator collaborator; public void perform(Model model) { boolean value = collaborator.collaborate(model.getInfo()); collaborator.receive(value); } }

И кодът на теста в крайна сметка ще бъде като:

@RunWith(JMockit.class) public class PerformerTest { @Injectable private Collaborator collaborator; @Tested private Performer performer; @Test public void testThePerformMethod(@Mocked Model model) { new Expectations() {{ model.getInfo();result = "bar"; collaborator.collaborate("bar"); result = true; }}; performer.perform(model); new Verifications() {{ collaborator.receive(true); }}; } }

4. Заключение

С това ще завършим нашето практическо въведение в JMockit. Ако искате да научите повече за JMockit, следете за бъдещи статии.

Пълното изпълнение на този урок може да бъде намерено в проекта GitHub.

4.1. Статии от поредицата

Всички статии от поредицата:

  • JMockit 101
  • Ръководство за JMockit - Очаквания
  • Разширено използване на JMockit