Главная страница
Навигация по странице:

  • Пример JUnit тестирования

  • JUnit и фреймворк Mockito

  • Функциональное тестирование

  • Интеграционное тестирование

  • Mockito

  • Синтаксис создания заглушки Mockito

  • Методы Mockito в примерах Для рассмотрения методов фреймворка Mockito

  • Листинги тестового класса и интерфейса

  • Basic Java Tools for Building & Testing Apps


    Скачать 4.76 Mb.
    НазваниеBasic Java Tools for Building & Testing Apps
    АнкорJUNIt
    Дата14.11.2022
    Размер4.76 Mb.
    Формат файлаpdf
    Имя файла5_2_0_Maven_JUnit_Tutorial.pdf
    ТипРеферат
    #787190
    страница10 из 16
    1   ...   6   7   8   9   10   11   12   13   ...   16
    Список типов проверок Asserts

    Тип проверки
    Описание
    fail() fail(String message) прерывание теста с ошибкой, т.е. тест будет неудачным assertTrue(boolean condition) assertTrue(java.lang.String message, boolean condition) проверка на равенство условия condition значению true assertFalse(boolean condition) assertFalse(String message, boolean condition) проверка на равенство условия condition значению false assertEquals(<тип> expected, <тип> actual) assertEquals(String message, <тип> expected, <тип> actual) проверка на равенство; <тип> — это Object, int, double и т.д. assertArrayEquals(byte[] expecteds, byte[] actuals) assertArrayEquals(String message, <тип>[] expecteds, <тип>[] actuals) проверка массивов на равенство; аналогично assertEquals; <тип> — это Object, int, double и т.д. assertNotNull(Object object) assertNotNull(String message, Object object) проверка, что Object не null assertNull(Object object) assertNull(String message, Object object) проверка, что Object null assertSame(Object expected, Object actual) assertSame(String message, Object expected, Object actual) проверка на равенство двух объектов expected и actual, т.е. один и тот же объект
    Пример JUnit тестирования
    Для демонстрации основных возможностей JUnit, используем примитивный java класс
    FuncMath, который имеет два метода - нахождение факториала неотрицательного числа и суммы двух чисел. Кроме того, в экземпляре класса будет находится счетчик вызовов методов. public class
    FuncMath
    {
    int calls
    ;
    public int getCalls
    ()
    {
    return calls
    ;
    }
    public long factorial
    (
    int number
    )
    {
    calls
    ++;
    if
    (
    number
    <
    0
    )
    throw new
    IllegalArgumentException
    ();
    long result
    =
    1
    ;
    if
    (
    number
    >
    1
    )
    {
    for
    (
    int i
    =
    1
    ;
    i
    <
    =
    number
    ;
    i
    ++)
    result
    =
    result
    *
    i
    ;
    }
    return result
    ;
    }
    public long plus
    (
    int num1
    ,
    int num2
    )
    {
    calls
    ++;
    return num1
    +
    num2
    ;
    }
    }
    Иногда для выполнения каждого тестового сценария необходим некоторый контекст, например, заранее созданные экземпляры классов. А после выполнения нужно освободить зарезервированные ресурсы. В этом случае используют аннтоации @Before и @After. Метод, помеченный @Before будет выполняться перед каждым тестовым случаем, а метод, помеченный @After - после каждого тестового случая. Если же инициализацию и освобождение ресурсов нужно сделать всего один раз - соответственно до и после всех тестов
    - то используют пару аннотаций @BeforeClass и @AfterClass.
    Тестовый класс с несколькими сценариями будет иметь следующий вид : import org junit
    Test
    ;
    import org junit
    After
    ;
    import org junit
    Before
    ;
    import org junit
    Assert
    ;
    import org junit
    AfterClass
    ;
    import org junit
    BeforeClass
    ;
    public class
    JUnit_funcMath extends
    Assert
    {
    private
    FuncMath math
    ;
    @Before public void init
    ()
    {
    math
    =
    new
    FuncMath
    ();
    }
    @After public void tearDown
    ()
    {
    math
    =
    null
    ;
    }
    @Test public void calls
    ()
    {
    assertEquals
    (
    "math.getCalls() != 0"
    ,
    0
    ,
    dao getConnection
    ());
    math factorial
    (
    1
    );
    assertEquals
    (
    1
    ,
    math getCalls
    ());
    math factorial
    (
    1
    );
    assertEquals
    (
    2
    ,
    math getCalls
    ());
    }
    @Test public void factorial
    ()
    {
    assertTrue
    (
    math factorial
    (
    0
    )
    ==
    1
    );
    assertTrue
    (
    math factorial
    (
    1
    )
    ==
    1
    );
    assertTrue
    (
    math factorial
    (
    5
    )
    ==
    120
    );
    }
    @Test
    (
    expected
    =
    IllegalArgumentException class
    )
    public void factorialNegative
    ()
    {
    math factorial
    (-
    1
    );
    }
    @Ignore

    @Test public void todo
    ()
    {
    assertTrue
    (
    math plus
    (
    1
    ,
    1
    )
    ==
    3
    );
    }
    }
    Метод calls тестирует правильность счетчика вызовов. Метод factorial проверяет правильность вычисления факториала для некоторых стандартных значений. Метод factorialNegative проверяет, что для отрицательных значений факотриала будет брошен
    IllegalArgumentException. Метод todo будет проигнорирован.
    В заключении следует отметить, что в статье представлены не все возможности использования JUnit. Но как видно из приведенных примеров, фреймворк достаточно прост в использовании, дополнительных возможностей немного, но есть возможность расширения с помощью правил и запускалок

    JUnit и фреймворк Mockito
    Разработчикам программного обеспечения на разных этапах своей деятельности приходится сталкиваться с тремя стратегиями тестирования
    : функциональным, интеграционным и модульным тестированием. Все они используются для тестирования приложений разными способами, и каждая из стратегий имеет определенную цель. К сожалению, ни одна из стратегий не даёт стопроцентной гарантии обнаружения всех имеющихся ошибок. И даже комбинация всех трёх стратегий не может дать такой гарантии.
    Но их сочетание позволяет существенно снизить количество ошибок и убедить разработчика, что приложение функционирует согласно предъявленным требованиям.
    Функциональное тестирование
    Проведение функционального тестирования, как правило, связано с созданием специальной группы специалистов, занимающихся тестированием. На этом этапе приложение развертывается в действующем окружении и проверяется его соответствие ТЗ (Техническому
    Заданию) и предъявленным функциональным требованиям. Команда тестеровщиков использует комплекс автоматизированных и ручных тестов.
    Автоматизировать процесс функционального тестирования можно, если приложение включает
    API (Application Programming Interface) - интерфейс прикладного программирования, на котором оно построено. Однако наличие интерфейса в приложении (desktop, web) существенно снижает возможности полной автоматизации данного процесса.
    Интеграционное тестирование
    Стратегия интеграционного тестирования основывается на проверке прикладного кода в окружении, близком к фактическому окружению, но не являющимся им. Главная цель данной стратегии – убедиться в правильности взаимодействия кода с внешними ресурсами и взаимодействия различных технологий в приложении между собой.
    В интеграционном тестировании не требуется использовать фиктивные данные, как при модульном тестировании. Вместо этого в интеграционных тестах часто используются базы данных, находящиеся в памяти, которые легко можно создавать и уничтожать во время выполнения тестов. База данных в памяти – это самая настоящая база данных, что дает возможность проверить правильность работы сущностей JPA. Но все же эта база данных не совсем настоящая – она лишь имитирует настоящую базу данных для целей интеграционного тестирования.
    Модульное тестирование
    Целью модульного тестирования является проверка работы прикладной логики всего приложения или отдельных его частей при разных исходных данных, и анализ правильности получаемых результатов. Несмотря на то, что цель модульного тестирования выглядит простой и понятной, реализация этого типа тестирования может оказаться очень сложным и запутанным делом, особенно при наличии «старого» кода. Основные приемы проведения модульного тестирования опираются на следующие базовые принципы :

    внешние ресурсы не используются, т.е. недопустимо подключение к базам данных, веб-службам и т.п.;

    каждый класс имеет свой тест;

    тестируются только общедоступные методы или интерфейсы, а внутренний код тестируется за счет изменения входных данных;

    для получения данных, требуемых тестируемой логике, должны создаваться фиктивные зависимости.
    При проведении модульного тестирования для создания фиктивных классов-зависимостей можно использовать простой, но мощный фреймворк Mockito совместно с
    JUnit
    Фреймворк Mockito

    Фреймворк Mockito предоставляет ряд возможностей для создания заглушек вместо реальных классов или интерфейсов при написании JUnit тестов. Mockito можно скачать с сайта https://code.google.com/p/mockito
    , либо определить в зависимостях (dependencies) в maven проекте :


    org.mockito


    mockito-core


    1.9.5


    test


    Наибольшее распространение получили следующие возможности Mockito :

    создание заглушек для классов и интерфейсов;

    проверка вызыва метода и значений передаваемых методу параметров;

    использование концепции «частичной заглушки», при которой заглушка создается на класс с определением поведения, требуемое для некоторых методов класса;

    подключение к реальному классу «шпиона» spy для контроля вызова методов.
    Синтаксис создания заглушки Mockito
    Чтобы создать Mockito объект можно использовать либо аннотацию
    @Mock, либо метод mock.
    В следующем примере в двух разных классах (Test_Mockito1, Test_Mockito2) разными способами создаются объекты mcalc для имитации интерфейса калькулятора ICalculator. import org mockito
    Mock
    ;
    import org mockito
    Mockito
    ;
    import com example
    ICalculator
    ;
    public class
    Test_Mockito1
    {
    @Mock
    ICalculator mcalc
    ;
    }
    ----------------------------------------------------------- public class
    Test_Mockito2
    {
    ICalculator mcalc
    =
    Mockito mock
    (
    ICalculator class
    );
    }
    Если использовать статический импорт
    Mockito, то синтаксис будет иметь следующий вид : import static org mockito
    Mockito
    .*;
    import com example
    ICalculator
    ;
    public class
    Test_Mockito
    {
    ICalculator mcalc
    =
    mock
    (
    ICalculator class
    );
    }
    ПРИМЕЧАНИЕ : помните, что методы mock объекта возвращают значения по умолчанию : false
    для boolean, 0 для int, пустые коллекции, null для остальных объектов.
    Методы Mockito в примерах

    Для рассмотрения методов фреймворка Mockito будем использовать в качестве тестового класса калькулятор, реализующий интерфейс ICalculator. В следующем коде представлены листинги интерфейса ICalculator и класса Calculator.
    Листинги тестового класса и интерфейса
    public interface
    ICalculator
    {
    public double add
    (
    double d1
    ,
    double d2
    );
    public double subtract
    (
    double d1
    ,
    double d2
    );
    public double multiply
    (
    double d1
    ,
    double d2
    );
    public double divide
    (
    double d1
    ,
    double d2
    );
    }
    //--------------------------------------------------- public class
    Calculator
    {
    ICalculator icalc
    ;
    public
    Calculator
    (
    ICalculator icalc
    )
    {
    this icalc
    =
    icalc
    ;
    }
    public double add
    (
    double d1
    ,
    double d2
    )
    {
    return icalc add
    (
    d1
    ,
    d2
    );
    }
    public double subtract
    (
    double d1
    ,
    double d2
    )
    {
    return icalc subtract
    (
    d1
    ,
    d2
    );
    }
    public double multiply
    (
    double d1
    ,
    double d2
    )
    {
    return icalc multiply
    (
    d1
    ,
    d2
    );
    }
    public double divide
    (
    double d1
    ,
    double d2
    )
    {
    return icalc divide
    (
    d1
    ,
    d2
    );
    }
    public double double15
    ()
    {
    return
    15.0
    ;
    }
    }
    Как видно из листингов все методы калькулятора (add, subtract, multiply, divide), за исключением одного, возвращают не вычисленные значения, а результаты выполнения данных методов в объекте, реализующим интерфейс ICalculator, который в наших тестах будет представлять заглушка mcalc. Последний метод double15() должен вернуть реальное значение.
    1. Определение поведения - when(mock).thenReturn(value)
    Этот метод позволяет определить возвращаемое значение при вызове метода mock с заданными параметрами. Если будет указано более одного возвращаемого значения, то они будут возвращены методом последовательно, пока не вернётся последнее; после этого при последующих вызовах будет возвращаться только последнее значение. Таким образом, чтобы метод всегда возвращал одно и то же значение, седует просто определить одно условие.
    @RunWith
    (
    MockitoJUnitRunner class
    )
    public class
    Test_Mockito
    {
    @Mock
    ICalculator mcalc
    ;
    // используем аанотацию @InjectMocks для создания mock объекта
    @InjectMocks
    Calculator calc
    =
    new
    Calculator
    (
    mcalc
    );
    @Test public void testCalcAdd
    ()

    {
    // определяем поведение калькулятора для операции сложения when
    (
    calc add
    (
    10.0
    ,
    20.0
    )).
    thenReturn
    (
    30.0
    );
    // проверяем действие сложения assertEquals
    (
    calc add
    (
    10
    ,
    20
    ),
    30.0
    ,
    0
    );
    // проверяем выполнение действия verify
    (
    mcalc
    ).
    add
    (
    10.0
    ,
    20.0
    );
    // определение поведения с использованием doReturn doReturn
    (
    15.0
    ).
    when
    (
    mcalc
    ).
    add
    (
    10.0
    ,
    5.0
    );
    // проверяем действие сложения assertEquals
    (
    calc add
    (
    10.0
    ,
    5.0
    ),
    15.0
    ,
    0
    );
    verify
    (
    mcalc
    ).
    add
    (
    10.0
    ,
    5.0
    );
    }
    }
    Метод verify позволяет проверить, была ли выполнена проверка с определенными параметрами. Если проверка не выполнялась или выполнялась с другими параметрами, то verify вызовет исключение.
    Для определения поведения mock в тесте была использована также следующая конструкция : doReturn
    (
    value
    ).
    when
    (
    mock
    ).
    method
    (
    params
    )
    2. Подсчет количества вызовов - atLeast, atLeastOnce, atMost, times, never
    Для проверки количества вызовов определенных методов Mockito предоставляет следующие методы :

    atLeast (int min) - не меньше min вызовов;

    atLeastOnce () - хотя бы один вызов;

    atMost (int max) - не более max вызовов;

    times (int cnt) - cnt вызовов;

    never () - вызовов не было;
    Следующий тест демонстрирует контроль количества вызовов метода subtract с разными параметрами. Для этого сначала определяется поведение mock (при определенных параметрах выдавать соответствующие результаты), и выполняются проверки с использованием assertEquals. После этого выполняется проверка количества вызовов mock с определенными параметрами. Две последние проверки не выполняются -
    «закомментированы». Если снять комментарий хотя бы с одной из них, то метод verify, вызовет исключение. Комментарий к этим проверкам описывает причину вызова методом исключения.
    @Test public void testCallMethod
    ()
    {
    // определяем поведение (результаты)
    when
    (
    mcalc subtract
    (
    15.0
    ,
    25.0
    )).
    thenReturn
    (
    10.0
    );
    when
    (
    mcalc subtract
    (
    35.0
    ,
    25.0
    )).
    thenReturn
    (-
    10.0
    );
    // вызов метода subtract и проверка результата assertEquals
    (
    calc subtract
    (
    15.0
    ,
    25.0
    ),
    10
    ,
    0
    );
    assertEquals
    (
    calc subtract
    (
    15.0
    ,
    25.0
    ),
    10
    ,
    0
    );
    assertEquals
    (
    calc subtract
    (
    35.0
    ,
    25.0
    ),-
    10
    ,
    0
    );
    // проверка вызова методов verify
    (
    mcalc
    ,
    atLeastOnce
    ()).
    subtract
    (
    35.0
    ,
    25.0
    );
    verify
    (
    mcalc
    ,
    atLeast
    (
    2
    )).
    subtract
    (
    15.0
    ,
    25.0
    );
    // проверка - был ли метод вызван 2 раза?
    verify
    (
    mcalc
    ,
    times
    (
    2
    )).
    subtract
    (
    15.0
    ,
    25.0
    );
    // проверка - метод не был вызван ни разу verify
    (
    mcalc
    ,
    never
    ()).
    divide
    (
    10.0
    ,
    20.0
    );
    /* Если снять комментарий со следующей проверки, то
    * ожидается exception, поскольку метод "subtract"
    * с параметрами (35.0, 25.0) был вызван 1 раз
    */
    // verify(mcalc, atLeast (2)).subtract(35.0, 25.0);
    /* Если снять комментарий со следующей проверки, то
    * ожидается exception, поскольку метод "subtract"
    * с параметрами (15.0, 25.0) был вызван 2 раза, а
    * ожидался всего один вызов
    */
    // verify(mcalc, atMost (1)).subtract(15.0, 25.0);
    }
    3. Обработка исключений - when(mock).thenThrow()
    Mockito позволяет вызвать исключение при определенных условиях. Для этого необходимо использовать следующий синтаксис кода :
    // создаем исключение
    RuntimeException exception
    =
    new
    RuntimeException
    (
    "Division by zero"
    );
    // определение поведения для вызова исключения doThrow
    (
    exception
    ).
    when
    (
    mock
    ).
    divide
    (
    5.0
    ,
    0
    ));
    В представленном коде создали исключение
    RuntimeException. После этого определили условия вызова исключения - вызов метода деления на 0. В следующем тесте выполняется проверка метода divide. При делении на 0 вызывается исключение.
    @Test public void testDevide
    ()
    {
    when
    (
    mcalc divide
    (
    15.0
    ,
    3
    )).
    thenReturn
    (
    5.0
    );
    assertEquals
    (
    calc divide
    (
    15.0
    ,
    3
    ),
    5.0
    ,
    0
    );
    // проверка вызова метода verify
    (
    mcalc
    ).
    divide
    (
    15.0
    ,
    3
    );
    // создаем исключение
    RuntimeException exception
    =
    new
    RuntimeException
    (
    "Division by zero"
    );
    // определяем поведение doThrow
    (
    exception
    ).
    when
    (
    mcalc
    ).
    divide
    (
    15.0
    ,
    0
    );
    assertEquals
    (
    calc divide
    (
    15.0
    ,
    0
    ),
    0.0
    ,
    0
    );
    verify
    (
    mcalc
    ).
    divide
    (
    15.0
    ,
    0
    );
    }
    4. Использование интерфейса org.mockito.stubbing.Answer
    Иногда описание поведения mock объекта требует определенной проверки с усложнением логики. В этом случае можно использовать интерфейс Answer, который позволяет реализовать заглушки методов со сложным поведением. В следующем тесте testThenAnswer при вызове метода сложения с определенными параметрами mcalc.add(11.0, 12.0) будет вызван метод answer, который подготовит ответ.
    Параметр InvocationOnMock позволяет получить информацию о вызываемом методе и параметрах.

    // метод обработки ответа private
    Answer
    <
    Double
    >
    answer
    =
    new
    Answer
    <
    Double
    >()
    {
    @Override public
    Double answer
    (
    InvocationOnMock invocation
    )
    throws
    Throwable
    {
    // получение объекта mock
    Object mock
    =
    invocation getMock
    ();
    System out println
    (
    "mock object : "
    +
    mock toString
    ());
    // аргументы метода, переданные mock
    Object
    []
    args
    =
    invocation getArguments
    ();
    double d1
    =
    (
    double
    )
    args
    [
    0
    ];
    double d2
    =
    (
    double
    )
    args
    [
    1
    ];
    double d3
    =
    d1
    +
    d2
    ;
    System out println
    (
    ""
    +
    d1
    +
    " + "
    +
    d2
    );
    return d3
    ;
    }
    };
    @Test public void testThenAnswer
    ()
    {
    // определение поведения mock для метода с параметрами when
    (
    mcalc add
    (
    11.0
    ,
    12.0
    )).
    thenAnswer
    (
    answer
    );
    assertEquals
    (
    calc add
    (
    11.0
    ,
    12.0
    ),
    23.0
    ,
    0
    );
    }
    5. Использование шпиона spy на реальных объектах
    Mockito позволяет подключать к реальным объектам «шпиона»
    1   ...   6   7   8   9   10   11   12   13   ...   16


    написать администратору сайта