Basic Java Tools for Building & Testing Apps
Скачать 4.76 Mb.
|
spy, контролировать возвращаемые методами значения и отслеживать количество вызовов методов. В следующем тесте создадим шпиона scalc, который подключим к реальному калькулятору и будем вызывать метод double15(). Необходимо отметить, что метод реального объекта double15 должен вернуть значение 15. Однако Mockito позволяет переопределить значение и согласно вновь назначенному условию новое значение должно быть 23. @Test public void testSpy () { Calculator scalc = spy ( new Calculator ()); when ( scalc double15 ()). thenReturn ( 23.0 ); // вызов метода реального класса scalc double15 (); // проверка вызова метода verify ( scalc ). double15 (); // проверка возвращаемого методом значения assertEquals ( 23.0 , scalc double15 (), 0 ); // проверка вызова метода не менее 2-х раз verify ( scalc , atLeast ( 2 )). double15 (); } В результате выполнения теста видим, что метод возвращает значение 23. Таким образом, фреймворк Mockito в сочетании с JUnit можно использовать для тестов реального класса. При этом, можно проверить, вызывался ли метод, сколько раз и с какими параметрами. Кроме этого, можно создавать заглушки только для некоторых методов. Это позволяет проверить поведение одних методов, используя заглушки для других. 6. Проверка вызова метода с задержкой, timeout Фреймворк Mockito позволяет выполнить проверку вызова определенного метода в течение заданного в timeout времени. Задержка времени определяется в милисекундах. @Test public void testTimout () { // определение результирующего значения mock для метода when ( mcalc add ( 11.0 , 12.0 )). thenReturn ( 23.0 ); // проверка значения assertEquals ( calc add ( 11.0 , 12.0 ), 23.0 , 0 ); // проверка вызова метода в течение 10 мс verify ( mcalc , timeout ( 100 )). add ( 11.0 , 12.0 ); } 7. Использование в тестах java классов В следующем тесте при создании mock объектов используются java классы Iterator и Comparable. После этого определяются условия проверок и выполняются тесты. @Test public void testJavaClasses () { // создание объекта mock Iterator < String > mis = mock ( Iterator class ); // формирование ответов when ( mis next ()). thenReturn ( "Привет" ). thenReturn ( "Mockito" ); // формируем строку из ответов String result = mis next () + ", " + mis next (); // проверяем assertEquals ( "Привет, Mockito" , result ); Comparable < String > mcs = mock ( Comparable class ); when ( mcs compareTo ( "Mockito" )). thenReturn ( 1 ); assertEquals ( 1 , mcs compareTo ( "Mockito" )); Comparable < Integer > mci = mock ( Comparable class ); when ( mci compareTo ( anyInt ())). thenReturn ( 1 ); assertEquals ( 1 , mci compareTo ( 5 )); } Краткое руководство по BDDMockito Testing Mockito FacebookTumblrPinterestPocketEvernoteTwitterLineEmailRedditDiggVKРесурс 1. Обзор Термин BDD был впервые введен Dan North - в 2006 году BDD поощряет написание тестов на естественном, понятном человеку языке, ориентированном на поведение приложения Он определяет четко структурированный способ написания тестов в следующих трех разделах (Arrange, Act, Assert): given некоторые предварительные условия (Arrange) when действие происходит (закон) then проверить вывод (Утвердить) Библиотека Mockito поставляется с классом BDDMockito , который представляет дружественные к BDD API. ** Этот API позволяет нам использовать более дружественный к BDD подход, организуя наши тесты с помощью given () и делая утверждения с помощью then () . В этой статье мы собираемся объяснить, как настроить наши тесты Mockito на основе BDD. Мы также поговорим о различиях между API Mockito и BDDMockito , чтобы в конечном итоге сосредоточиться на API BDDMockito . 2. Настроить 2.1. Зависимости Maven BDD-версия Mockito является частью библиотеки mockito-core ** , чтобы начать, нам просто нужно включить артефакт: < dependency > < groupId >org.mockito groupId > < artifactId >mockito-core artifactId > < version >2.21.0 version > dependency > Для получения последней версии Mockito, пожалуйста, проверьте Maven Центральная 2.2. Импорт Наши тесты могут стать более читабельными, если мы включим следующий статический импорт: import static org.mockito.BDDMockito.** ; Обратите внимание, что BDDMockito расширяет Mockito , поэтому мы не пропустим ни одной функции, предоставляемой традиционным Mockito API. 3. Мокито против BDDMockito Традиционный макет в Mockito выполняется с помощью when (obj) . then ** () на шаге Arrange. Позже, взаимодействие с нашим макетом может быть проверено с помощью verify () на шаге Assert. BDDMockito предоставляет псевдонимы BDD для различных методов Mockito , поэтому мы можем написать наш шаг Arrange, используя given (вместо when ), также мы можем написать наш шаг Assert, используя then (вместо verify ). Давайте рассмотрим пример тестового тела с использованием традиционного Mockito: when(phoneBookRepository.contains(momContactName)) .thenReturn( false ); phoneBookService.register(momContactName, momPhoneNumber); verify(phoneBookRepository) .insert(momContactName, momPhoneNumber); Давайте посмотрим, как это можно сравнить с BDDMockito : given(phoneBookRepository.contains(momContactName)) .willReturn( false ); phoneBookService.register(momContactName, momPhoneNumber); then(phoneBookRepository) .should() .insert(momContactName, momPhoneNumber); 4. Дразнить с BDDMockito Давайте попробуем протестировать PhoneBookService , где нам нужно будет посмеяться над PhoneBookRepository: public class PhoneBookService { private PhoneBookRepository phoneBookRepository; public void register (String name, String phone) { if (!name.isEmpty() && !phone.isEmpty() && !phoneBookRepository.contains(name)) { phoneBookRepository.insert(name, phone); } } public String search (String name) { if (!name.isEmpty() && phoneBookRepository.contains(name)) { return phoneBookRepository.getPhoneNumberByContactName(name); } return null ; } } BDDMockito as Mockito позволяет нам возвращать значение, которое может быть фиксированным или динамическим. Это также позволило бы нам создать исключение: 4.1. Возврат фиксированного значения Используя BDDMockito, мы могли бы легко настроить Mockito для возврата фиксированного результата всякий раз, когда вызывается наш целевой метод ложного объекта: given(phoneBookRepository.contains(momContactName)) .willReturn( false ); phoneBookService.register(xContactName, "" ); then(phoneBookRepository) .should(never()) .insert(momContactName, momPhoneNumber); 4.2. Возврат динамического значения BDDMockito позволяет нам предоставить более сложный способ возврата значений. Мы могли бы вернуть динамический результат на основе ввода: given(phoneBookRepository.contains(momContactName)) .willReturn( true ); given(phoneBookRepository.getPhoneNumberByContactName(momContactName)) .will((InvocationOnMock invocation) -> invocation.getArgument( 0 ).equals(momContactName) ? momPhoneNumber : null ); phoneBookService.search(momContactName); then(phoneBookRepository) .should() .getPhoneNumberByContactName(momContactName); 4.3. Бросать исключение Сказать, что Mockito сгенерирует исключение, довольно просто: given(phoneBookRepository.contains(xContactName)) .willReturn( false ); willThrow( new RuntimeException()) .given(phoneBookRepository) .insert(any(String.class), eq(tooLongPhoneNumber)); try { phoneBookService.register(xContactName, tooLongPhoneNumber); fail( "Should throw exception" ); } catch (RuntimeException ex) { } then(phoneBookRepository) .should(never()) .insert(momContactName, tooLongPhoneNumber); Обратите внимание, как мы поменялись местами given и will ** , что является обязательным в случае, если мы высмеиваем метод, который не имеет возвращаемого значения. Также обратите внимание, что мы использовали сопоставители аргументов, такие как ( any , eq ), чтобы обеспечить более общий способ насмешки, основанный на критериях, а не на фиксированном значении. 5. Заключение В этом кратком руководстве мы обсудили, как BDDMockito пытается создать сходство BDD с нашими тестами Mockito, и обсудили некоторые различия между Mockito и BDDMockito . Как всегда, исходный код можно найти over на GitHub - в тестовом пакете com.baeldung.bddmockito Junit 5. Basic Annotation_Description'>Annotations JUnit Jupiter supports the following annotations for configuring tests and extending the framework. Unless otherwise stated, all core annotations are located in the org.junit.jupiter.api package in the junit-jupiter-api module. Annotation Description @Test Denotes that a method is a test method. Unlike JUnit 4’s @Test annotation, this annotation does not declare any attributes, since test extensions in JUnit Jupiter operate based on their own dedicated annotations. Such methods are inherited unless they are overridden. @Parameterized Test Denotes that a method is a parameterized test . Such methods are inherited unless they are overridden. @RepeatedTest Denotes that a method is a test template for a repeated test . Such methods are inherited unless they are overridden. @TestFactory Denotes that a method is a test factory for dynamic tests . Such methods are inherited unless they are overridden. @TestTemplate Denotes that a method is a template for test cases designed to be invoked multiple times depending on the number of invocation contexts returned by the registered providers . Such methods are inherited unless they are overridden. @TestMethodOrd er Used to configure the test method execution order for the annotated test class; similar to JUnit 4’s @FixMethodOrder . Such annotations are inherited. @TestInstance Used to configure the test instance lifecycle for the annotated test class. Such annotations are inherited. @DisplayName Declares a custom display name for the test class or test method. Such annotations are not inherited. @DisplayNameGe neration Declares a custom display name generator for the test class. Such annotations are inherited. @BeforeEach Denotes that the annotated method should be executed before each @Test , @RepeatedTest , @ParameterizedTest , or @TestFactory method in the current class; analogous to JUnit 4’s @Before . Such methods are inherited unless they are overridden. @AfterEach Denotes that the annotated method should be executed after each @Test , @RepeatedTest , @ParameterizedTest , or @TestFactory method in the current class; analogous to JUnit 4’s @After . Such methods are inherited unless they are overridden. Annotation Description @BeforeAll Denotes that the annotated method should be executed before all @Test , @RepeatedTest , @ParameterizedTest , and @TestFactory methods in the current class; analogous to JUnit 4’s @BeforeClass . Such methods are inherited (unless they are hidden or overridden) and must be static (unless the "per-class" test instance lifecycle is used). @AfterAll Denotes that the annotated method should be executed after all @Test , @RepeatedTest , @ParameterizedTest , and @TestFactory methods in the current class; analogous to JUnit 4’s @AfterClass . Such methods are inherited (unless they are hidden or overridden) and must be static (unless the "per-class" test instance lifecycle is used). @Nested Denotes that the annotated class is a non-static nested test class @BeforeAll and @AfterAll methods cannot be used directly in a @Nested test class unless the "per-class" test instance lifecycle is used. Such annotations are not inherited. @Tag Used to declare tags for filtering tests , either at the class or method level; analogous to test groups in TestNG or Categories in JUnit 4. Such annotations are inherited at the class level but not at the method level. @Disabled Used to disable a test class or test method; analogous to JUnit 4’s @Ignore Such annotations are not inherited. @Timeout Used to fail a test, test factory, test template, or lifecycle method if its execution exceeds a given duration. Such annotations are inherited. @ExtendWith Used to register extensions declaratively . Such annotations are inherited. @RegisterExten sion Used to register extensions programmatically via fields. Such fields are inherited unless they are shadowed. @TempDir Used to supply a temporary directory via field injection or parameter injection in a lifecycle method or test method; located in the org.junit.jupiter.api.io package. Some annotations may currently be experimental. Consult the table in Experimental APIs for details. Meta-Annotations and Composed Annotations JUnit Jupiter annotations can be used as meta-annotations. That means that you can define your own composed annotation that will automatically inherit the semantics of its meta-annotations. For example, instead of copying and pasting @Tag("fast") throughout your code base (see Tagging and Filtering ), you can create a custom composed annotation named @Fast as follows. @Fast can then be used as a drop-in replacement for @Tag("fast") import java.lang.annotation.ElementType ; import java.lang.annotation.Retention ; import java.lang.annotation.RetentionPolicy ; import java.lang.annotation.Target ; import org.junit.jupiter.api.Tag ; @Target ({ ElementType . TYPE , ElementType . METHOD }) @Retention ( RetentionPolicy . RUNTIME ) @Tag ( "fast" ) public @interface Fast { } The following @Test method demonstrates usage of the @Fast annotation. @Fast @Test void myFastTest () { // ... } You can even take that one step further by introducing a custom @FastTest annotation that can be used as a drop-in replacement for @Tag("fast") and @Test import java.lang.annotation.ElementType ; import java.lang.annotation.Retention ; import java.lang.annotation.RetentionPolicy ; import java.lang.annotation.Target ; import org.junit.jupiter.api.Tag ; import org.junit.jupiter.api.Test ; @Target ( ElementType . METHOD ) @Retention ( RetentionPolicy . RUNTIME ) @Tag ( "fast" ) @Test public @interface FastTest { } JUnit automatically recognizes the following as a @Test method that is tagged with "fast". @FastTest void myFastTest () { // ... } Переход с JUnit 4 на JUnit 5 Testing JUnit 5 FacebookTumblrPinterestPocketEvernoteTwitterLineEmailRedditDiggVKРесурс 1. Обзор В этой статье мы увидим, как мы можем перейти с JUnit 4 на последнюю версию JUnit 5 - с обзором различий между двумя версиями библиотеки. Общие рекомендации по использованию JUnit 5 см. В нашей ссылке на статью:/junit-5[здесь]. 2. JUnit 5 Преимущества Давайте начнем с предыдущей версии - JUnit 4 имеет некоторые явные ограничения: Вся структура содержалась в одной библиотеке jar. Целый Библиотека должна быть импортирована, даже если требуется. В JUnit 5 мы получаем больше детализации и можем импортировать только то, что является необходимым ** Один исполнитель тестов может одновременно выполнять тесты только в JUnit 4 (например, SpringJUnit4ClassRunner или Parameterized ). JUnit 5 позволяет несколько бегунов работать одновременно ** JUnit 4 никогда не выходил за пределы Java 7, пропуская множество функций из Java 8. JUnit 5 хорошо использует функции Java 8 Идея JUnit 5 заключалась в том, чтобы полностью переписать JUnit 4, чтобы устранить большинство из этих недостатков. 3. Отличия JUnit 4 был разделен на модули, которые составляют JUnit 5: JUnit Platform - этот модуль охватывает все платформы расширений, которые мы может быть заинтересован в выполнении теста, обнаружения и отчетности JUnit Vintage - ** этот модуль обеспечивает обратную совместимость с JUnit 4 или даже JUnit 3 3.1. Аннотации JUnit 5 содержит важные изменения в своих аннотациях. |