- Санҷиши ҳамгироии пойгоҳи додаҳо бо истифода аз MariaDB барои иваз кардани MySql
- Татбиқи замимаи бисёрзабонӣ
- Захираи файлҳо дар барнома ва маълумот дар бораи онҳо дар пойгоҳи додаҳо
Намудҳои санҷиш
Санҷиш чист? Тавре ки Wiki мегӯяд: " Санҷиш ё санҷиш як роҳи омӯзиши равандҳои аслии система тавассути ҷойгир кардани система дар ҳолатҳои гуногун ва пайгирии тағироти мушоҳидашаванда дар он мебошад." Ба ибораи дигар, ин санҷиши кори дурусти системаи мо дар ҳолатҳои муайян аст. Хуб, биёед бубинем, ки кадом намуди санҷишҳо мавҷуданд:-
Санҷиши воҳидҳо санҷишест, ки вазифаи онҳо санҷиши ҳар як модули система аст. Ин матлуб аст, ки ин қисмҳои ҳадди ақал тақсимшавандаи система мебошанд, масалан, модулҳо.
-
Санҷиши система санҷиши сатҳи баланд барои санҷиши кори як қисми калонтари барнома ё дар маҷмӯъ система мебошад.
-
Санҷиши регрессия санҷишест, ки барои тафтиш кардани он истифода мешавад, ки оё хусусиятҳои нав ё ислоҳи хатогиҳо ба функсияҳои мавҷудаи барнома таъсир мерасонанд ва оё хатогиҳои кӯҳна дубора пайдо мешаванд.
-
Санҷиши функсионалӣ ин санҷиши мутобиқати як қисми барнома ба талаботҳои дар мушаххасот, ҳикояҳои корбарон ва ғайра зикршуда мебошад.
Намудҳои санҷиши функсионалӣ:
- санҷиши "қуттии сафед" барои мутобиқати қисми барнома ба талабот бо донистани татбиқи дохorи система;
- Санҷиши "қуттии сиёҳ" барои мутобиқати қисми барнома ба талабот бидуни огоҳии татбиқи дохorи система.
- Санҷиши самаранокӣ як намуди санҷишҳоест, ки барои муайян кардани суръати кор бо як система ё як қисми он дар зери сарбории муайян навишта шудаанд.
- Санҷиши сарборӣ - озмоишҳо барои санҷидани устувории система дар зери бори стандартӣ ва дарёфти қуллаи ҳадди имкон, ки дар он барнома дуруст кор мекунад, пешбинӣ шудааст.
- Стресс-тестирование (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