- MySql-i əvəz etmək üçün MariaDB istifadə edərək verilənlər bazasının inteqrasiya sınağı
- Çoxdilli tətbiqin həyata keçirilməsi
- Faylların proqrama və onlar haqqında məlumatların verilənlər bazasına saxlanması
Test növləri
Test nədir? Wiki-nin dediyi kimi: “ Sınaq və ya test sistemi müxtəlif vəziyyətlərdə yerləşdirmək və orada müşahidə olunan dəyişiklikləri izləməklə sistemin əsas proseslərini öyrənmək üsuludur.” Başqa sözlə, bu, müəyyən vəziyyətlərdə sistemimizin düzgün işləməsinin testidir. Gəlin görək hansı test növləri var:-
Vahid sınağı, vəzifəsi sistemin hər bir modulunu ayrıca yoxlamaq olan testlərdir. Arzu edilir ki, bunlar sistemin minimal bölünə bilən hissələri, məsələn, modullar.
-
Sistem testi tətbiqin daha böyük bir hissəsinin və ya bütövlükdə sistemin işini yoxlamaq üçün yüksək səviyyəli testdir.
-
Reqressiya testi yeni funksiyaların və ya səhvlərin aradan qaldırılmasının tətbiqin mövcud funksionallığına təsir edib-etmədiyini və köhnə səhvlərin yenidən görünüb-görünmədiyini yoxlamaq üçün istifadə edilən sınaqdır.
-
Funksional sınaq tətbiqin bir hissəsinin spesifikasiyalarda, istifadəçi hekayələrində və s.-də göstərilən tələblərə uyğunluğunun yoxlanılmasıdır.
Funksional test növləri:
- sistemin daxili tətbiqi bilikləri ilə ərizənin bir hissəsinin tələblərə uyğunluğu üçün “ağ qutu” testi ;
- Tətbiqin bir hissəsinin sistemin daxili tətbiqindən xəbəri olmadan tələblərə uyğunluğu üçün "qara qutu" testi .
- Performans testi bir sistemin və ya onun bir hissəsinin müəyyən bir yük altında işləmə sürətini təyin etmək üçün yazılmış bir test növüdür.
- Yük testi - standart yüklər altında sistemin dayanıqlığını yoxlamaq və tətbiqin düzgün işlədiyi maksimum mümkün zirvəni tapmaq üçün hazırlanmış testlər.
- Стресс-тестирование (stress testing) — вид тестирования, предназначенный для проверки работоспособности applications при нестандартных нагрузках и для определения максимально возможного пика, при котором система не упадёт.
- Тестирование безопасности (security testing) — тесты, используемые для проверки безопасности системы (от атак хакеров, вирусов, несанкционированного доступа к конфиденциальным данным и прочих радостей жизни).
- Тестирование локализации (localization testing) — это тесты локализации для applications.
- Юзабorти тестирование (usability testing) — вид тестирования, направленный на проверку удобства использования, понятности, привлекательности и обучаемости для пользователей. Это всё звучит хорошо, но How оно происходит на практике? Все просто: используется пирамида тестирования Майка Кона: Это упрощенный вариант пирамиды: сейчас её делят на более мелкие детали. Но сегодня мы не будем извращаться и рассмотрим самый простой вариант.
-
Unit — модульные тесты, применяемые в различных слоях applications, тестирующие наименьшую делимую логику applications: например, класс, но чаще всего — метод. Эти тесты обычно стараются по максимуму изолировать от внешней логики, то есть создать иллюзию того, что остальная часть applications работает в стандартном режиме.
Данных тестов всегда должно быть много (больше, чем остальных видов), так How они тестируют маленькие кусочки и весьма легковесные, не кушающие много ресурсов (под ресурсами я имею виду оперативную память и время).
-
Integration — интеграционное тестирование. Оно проверяет более крупные кусочки системы, то есть это либо объединение нескольких кусочков логики (несколько методов or классов), либо корректность работы с внешним компонентом. Этих тестов How правило меньше, чем Unit, так How они тяжеловеснее.
Как пример интеграционных тестов можно рассмотреть соединение с базой данных и проверку правильной отработки методов, работающих с ней.
-
UI — тесты, которые проверяют работу пользовательского интерфейса. Они затрагивают логику на всех уровнях applications, из-за чего их еще называют сквозными. Их How правило в разы меньше, так они наиболее тяжеловесны и должны проверять самые необходимые (используемые) пути.
На рисунке выше мы видим соотношение площадей разных частей треугольника: примерно такая же пропорция сохраняется в количестве этих тестов в реальной работе.
Сегодня подробно рассмотрим самые используемые тесты — юнит-тесты, так How уметь ими пользоваться на базовом уровне должны все уважающие себя Java-разработчики.
- материал о Code Coverage на JavaRush и на Хабре;
- фундаментальная теория тестирования.
- Пишем наш тест.
- Запускаем тест, прошел он or нет (видим, что всё красное — не психуем: так и должно быть).
- Добавляем code, который должен удовлетворить данный тест (запускаем тест).
- Выполняем рефакторинг codeа.
- Задание тестируемых данных (фикстур).
- Использование тестируемого codeа (вызов тестируемого метода).
- Проверка результатов и сверка с ожидаемыми.
assertEquals(Object expecteds, Object actuals)
— проверяет, равны ли передаваемые обьекты.assertTrue(boolean flag)
— проверяет, возвращает ли переданное meaning — true.assertFalse(boolean flag)
— проверяет, возвращает ли переданное meaning — false.assertNull(Object object)
– проверяет, является ли an object нулевым (null).assertSame(Object firstObject, Object secondObject)
— проверяет, ссылаются ли передаваемые значения на один и тот же обьект.assertThat(T t, Matcher<T> matcher)
— проверяет, удовлетворяет ли t условию, указанному в matcher.
Ключевые понятия юнит-тестирования
Покрытие тестов (Code Coverage) — одна из главных оценок качества тестирования applications. Это процент codeа, который был покрыт тестами (0-100%). На практике многие гонятся за этим процентом, с чем я не согласен, так How начинается навешивание тестов там, где они не нужны. Например, у нас в сервисе есть стандартные CRUD (create/get/update/delete) операции без дополнительной логики. Эти методы — сугубо посредники, делегирующие работу слою, работающему с репозиторием. В данной ситуации нам нечего тестировать: разве то, что вызывает ли данный метод — метод из дао, но это не серьёзно. Для оценки покрытия тестами обычно используют дополнительные инструменты: JaCoCo, Cobertura, Clover, Emma и т.д. Для более детального изучения данного вопроса держи пару годных статей:Этапы тестирования
Тест состоит из трёх этапов:Среды тестирования
Итак, теперь ближе к делу. Для Java доступно несколько сред тестирования (фреймворков). Самые популярные из них — JUnit и TestNG. Для нашего обзора мы используем: JUnit тест представляет собой метод, содержащийся в классе, который используется только для тестирования. Класс, How правило, называется так же, How и класс, который он тестирует с +Test в конце. Например, CarService→ CarServiceTest. Система сборки Maven автоматически включает такие классы в тестовую область. По сути этот класс и называется тестовым. Немного пройдёмся по базовым annotationм: @Test — определение данного метода в качестве тестируемого (по сути — метод, помеченный данной аннотацией и есть модульный тест). @Before — помечается метод, который будет выполняться перед каждым тестом. Например, заполнение тестовых данных класса, чтение входных данных и т. д. @After — ставится над методом, который будет вызывать после каждого теста (чистка данных, восстановление дефолтных значений). @BeforeClass — ставится над методом — аналог @Before. Но этот метод вызывается лишь однажды перед всеми тестами для данного класса и поэтому должен быть статическим. Он используется для выполнения более тяжелых операций, How например подъем тестовой БД. @AfterClass — противоположность @BeforeClass: исполняется один раз для данного класса, но исполняется после всех тестов. Используется, например, для очистки постоянных ресурсов or отключения от БД. @Ignore — отмечает, что метод ниже отключен и будет игнорироваться при общей прогонке тестов. Используется в разных случаях, например, если изменor базовый метод и не успели переделать под него тест. В таких случаях ещё желательно добавить описание — @Ignore("Some description"). @Test (expected = Exception.class) — используется для отрицательных тестов. Это тесты, которые проверяют, How ведёт себя метод в случае ошибки, то есть тест ожидает, что метод выкинет некоторое исключение. Такой метод обозначается аннотацией @Test, но с указанием ошибки для отлова. @Test(timeout=100) — проверяет, что метод исполняется не более чем 100 миллисекунд. @Mock — используется над полем класс для задания данного an object моком (это не из Junit библиотеки, а из Mockito), и если нам будет необходимо, мы зададим поведение мока в конкретной ситуации, непосредственно в методе теста. @RunWith(MockitoJUnitRunner.class) — метод ставится над классом. Он и является кнопкой для прогона тестов в нем. Runner-ы могут быть различными: например, есть такие: MockitoJUnitRunner, JUnitPlatform, SpringRunner и т. д.). В JUnit 5 аннотацию @RunWith заменor более мощной аннотацией @ExtendWith. Взглянем на некоторые методы сравнения результатов:assertThat(firstObject).isEqualTo(secondObject)
Здесь я рассказал о базовых методах, так How остальные — это различные вариации приведенных выше.
Практика тестирования
А теперь давайте рассмотрим приведенный выше материал на конкретном примере. Будем тестировать метод для сервиса — update. Рассматривать слой дао не будем, так How он у нас дефолтный. Добавим стартер для тестов:<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.2.2.RELEASE</version>
<scope>test</scope>
</dependency>
Итак, класс сервиса:
@Service
@RequiredArgsConstructor
public class RobotServiceImpl implements RobotService {
private final RobotDAO robotDAO;
@Override
public Robot update(Long id, Robot robot) {
Robot found = robotDAO.findById(id);
return robotDAO.update(Robot.builder()
.id(id)
.name(robot.getName() != null ? robot.getName() : found.getName())
.cpu(robot.getCpu() != null ? robot.getCpu() : found.getCpu())
.producer(robot.getProducer() != null ? robot.getProducer() : found.getProducer())
.build());
}
}
8 — вытягиваем обновляемый обьект из БД 9-14 — создаём an object через билдер, если в приходящем an objectе есть поле — задаем его, если нет — оставляем то, что есть в БД И смотрим наш тест:
@RunWith(MockitoJUnitRunner.class)
public class RobotServiceImplTest {
@Mock
private RobotDAO robotDAO;
private RobotServiceImpl robotService;
private static Robot testRobot;
@BeforeClass
public static void prepareTestData() {
testRobot = Robot
.builder()
.id(123L)
.name("testRobotMolly")
.cpu("Intel Core i7-9700K")
.producer("China")
.build();
}
@Before
public void init() {
robotService = new RobotServiceImpl(robotDAO);
}
1 — наш Runner 4 — изолируем сервис от слоя дао, подставляя мок 11 — задаем для класса тестовую сущность (ту, которую мы будем юзать в качестве испытуемого хомячка) 22 — задаём an object сервиса, который мы и будем тестить
@Test
public void updateTest() {
when(robotDAO.findById(any(Long.class))).thenReturn(testRobot);
when(robotDAO.update(any(Robot.class))).then(returnsFirstArg());
Robot robotForUpdate = Robot
.builder()
.name("Vally")
.cpu("AMD Ryzen 7 2700X")
.build();
Robot resultRobot = robotService.update(123L, robotForUpdate);
assertNotNull(resultRobot);
assertSame(resultRobot.getId(),testRobot.getId());
assertThat(resultRobot.getName()).isEqualTo(robotForUpdate.getName());
assertTrue(resultRobot.getCpu().equals(robotForUpdate.getCpu()));
assertEquals(resultRobot.getProducer(),testRobot.getProducer());
}
Здесь мы видим четкое разделение теста на три части: 3-9 — задание фикстур 11 — выполнение тестируемой части 13-17 — проверка результатов Подробнее: 3-4 — задаём поведение для мока дао 5 — задаём экземпляр, который мы будем апдейтить поверх нашего стандартного 11 — используем метод и берём результирующий экземпляр 13 — проверяем, что он не ноль 14 — сверяем айди результата и заданные аргументы метода 15 — проверяем, обновилось ли Name 16 — смотрим результат по cpu 17 – так How в экземпляре для обновления мы не задавали это поле, оно должно остаться прежним, проверяем это. Запускаем: Тест зелёный, можно выдыхать)) Итак, подведём итоги: тестирование улучшает качество codeа и делает процесс разработки более гибким и надёжный. Представьте себе, How много сил мы потратим при изменении дизайна программного обеспечения с сотнями файлов классов. Когда у нас есть модульные тесты, написанные для всех этих классов, мы можем уверенно провести рефакторинг. И самое главное — это помогает нам легко находить ошибки во время разработки. Гайз, на этом у меня сегодня всё: сыпем лайки, пишем комменты)))
GO TO FULL VERSION