Тестирование ” блока ” в системе отдельно от других блоков.
Но Что Означает Единица Измерения ❓
Существует много разных мнений относительно ответа на этот вопрос.
- Некоторые люди говорят, что единица – это функция, некоторые говорят, что это класс.
🟢 Однако определение, которое я нахожу наиболее логичным, – это определение, описывающее единицу как “поведение” системы.
Это сценарий, который имеет значение в бизнес-логике.
Например, создайте новую отправку, используя входные данные клиента, и сохраните их в базе данных.
- на самом деле не спасать, а подделывать (издеваться), мы увидим это немного позже
Но Почему Описание Поведения Кажется Наиболее Логичным ❓
Тесты были бы ближе к реальной жизни ✔️
Вы бы не стали писать бесполезные тесты. (например, бесполезная проверка нулевого указателя) ✔️
Мы можем реорганизовать наш код, не нарушая тесты, так как мы тестируем выходные данные устройства, а не его внутреннюю работу ✔️
Однако есть некоторые вещи, которые мы, возможно, не захотим тестировать в подразделении 🔴
Как что?
Чаще всего – зависимость от внешнего мира.
- Подключение к базе данных (дайте мне запись с этим идентификатором)
- Вызовы API (вызовите API Twitter и получите все мои твиты)
Эти зависимости нам нужны для издеваться . Издевательство – это определение того, как зависимость должна действовать в определенных условиях.
- о, дорогое подключение к базе данных, пожалуйста, верните этот объект, если ваш метод x был вызван с параметром y.
Давайте посмотрим на пример ⚙️
У нас есть класс отгрузки 📦
@RequiredArgsConstructor
public class Shipment {
private final String productCode;
private final String owner;
private final int count;
}
Хранилище отгрузок для операций с базой данных 🗃
public class ShipmentRepository {
public Optional findShipment(String owner, String productCode) {
// mock method
return Optional.empty();
}
public void save(Shipment shipment) {
// mock method
}
}
Служба проверки подлинности 🔍
public class VerificationService {
public boolean shipmentIsntValid(String owner, String productCode, int count) {
return owner.isEmpty()
|| productCode.isEmpty()
|| count < 0;
}
}
Служба доставки грузов 🥋
@RequiredArgsConstructor
public class ShipmentService {
private final VerificationService verificationService;
private final ShipmentRepository shipmentRepository;
public String createAndSaveShipment(String owner, String productCode, int count){
if (verificationService.shipmentIsntValid(owner, productCode, count))
return "Shipment isn't valid";
if (shipmentExistInDB(owner, productCode))
return "Shipment Not Found";
createNewShipment(owner, productCode, count);
return "Shipment Is Created";
}
private void createNewShipment(String owner, String productCode, int count) {
Shipment shipment = new Shipment(owner, productCode, count);
shipmentRepository.save(shipment);
}
public boolean shipmentExistInDB(String owner, String productCode) {
return shipmentRepository.findShipment(owner, productCode).isPresent();
}
}
Для модульного тестирования мы будем использовать Junit 5 и Mockito.
Давайте рассмотрим плохой пример модульных тестов ❌
@ExtendWith(MockitoExtension.class)
public class UniTestTests {
@Mock
ShipmentRepository shipmentRepo;
@Test
public void givenData_DetectValidity(){
VerificationService verificationService = new VerificationService();
boolean result = verificationService.shipmentIsntValid("jhon", "3HFF", 2);
assertFalse(result);
}
@Test
public void givenData_DetectShipmentExistsInDB(){
ShipmentService shipmentService = new ShipmentService(new VerificationService(), shipmentRepo);
Shipment shipment = new Shipment("ahmed", "3HKK", 4);
doReturn(Optional.of(shipment)).when(shipmentRepo).findShipment("ahmed", "3HKK");
boolean result = shipmentService.shipmentExistInDB("ahmed", "3HKK");
assertTrue(result);
}
}
Почему эти плохие модульные тесты? Важно
- Служба отправки и служба проверки – это два тесно связанных метода, которые работают вместе для создания единого поведения (добавление новой отправки).
- Однако мы тестируем их изолированно, как в отдельных тестах.
Теперь давайте рассмотрим хороший пример модульного тестирования ✅
@ExtendWith(MockitoExtension.class)
public class UniTestTests {
@Mock
ShipmentRepository shipmentRepo;
@Test
public void givenShipmentData_CreateNewShipment(){
VerificationService verificationService = new VerificationService();
ShipmentService shipmentService = new ShipmentService(verificationService, shipmentRepo);
doReturn(Optional.empty()).when(shipmentRepo).findShipment("jalil", "3HXX");
doNothing().when(shipmentRepo).save(any());
String result = shipmentService.createAndSaveShipment("jalil", "3HXX", 10);
assertEquals("Shipment Is Created", result);
}
}
Подведем итог в нескольких словах 🖋
Модульный тест предназначен для проверки поведения функций в системе. Это может быть набор классов и функций, взаимодействующих вместе для создания такого поведения.
Исходный код на 🔗 GitHub
Оригинал: “https://dev.to/jarjanazy/how-to-unit-test-like-a-pro-59kj”