Тестування є важливою частиною розробки програмного забезпечення, яка допомагає забезпечити якість та стабільність коду.
На наших курсах тестування ПЗ ми докладно розглядаємо тему автоматизації тестування. А в даній статті ми розглянемо популярні бібліотеки для Unit та Integration тестування в Java.
JUnit - це основна бібліотека для юніт-тестування в Java. Вона допомагає забезпечити якість коду, перевіряючи окремі модулі програми на відповідність очікуваній поведінці. Ось декілька корисних можливостей JUnit:
@Test, @BeforeEach, @AfterEach, @BeforeAll та @AfterAll для визначення життєвого циклу тесту.Assert, який надає методи для перевірки результатів, такі як assertEquals, assertTrue, assertFalse та assertNull.Припустимо, у вас є клас Calculator з методом add, який приймає два цілих числа та повертає їх суму. Ось як можна написати юніт-тест JUnit для цього методу:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class CalculatorTest {
@Test
void testAdd() {
Calculator calculator = new Calculator();
int result = calculator.add(2, 3);
assertEquals(5, result);
}
}
Mockito - це потужна бібліотека для створення та управління об'єктами-замінниками (mocks) в Java. Вона дозволяє імітувати залежності та перевіряти їх взаємодію з тестируваними модулями. Ось декілька корисних функцій Mockito:
mock() або анотації @Mock.Припустимо, у вас є клас DataService, який залежить від іншого класу ExternalService для отримання даних. Ви хочете протестувати, що DataService коректно обробляє дані, отримані від ExternalService. Ось як можна використати Mockito для створення макету об'єкту ExternalService та перевірки його взаємодії з DataService:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;
class DataServiceTest {
@Test
void testGetData() {
ExternalService mockExternalService = mock(ExternalService.class);
when(mockExternalService.fetchData()).thenReturn("mock data");
DataService dataService = new DataService(mockExternalService);
String result = dataService.getData();
assertEquals("mock data", result);
verify(mockExternalService, times(1)).fetchData();
}
}
TestNG - це альтернативна бібліотека для юніт-тестування в Java, яка розширює можливості JUnit та надає додаткові функції, такі як:
Припустимо, у вас є клас UserService, який містить метод createUser. Ви хочете написати юніт-тест для перевірки валідації введених даних користувача. Ось як можна використати TestNG для створення тесту:
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
class UserServiceTest {
@DataProvider(name = "validUserData")
public Object[][] createValidUserData() {
return new Object[][] {
{"user1", "email1@example.com"},
{"user2", "email2@example.com"},
{"user3", "email3@example.com"}
};
}
@Test(dataProvider = "validUserData")
void testCreateUser(String username, String email) {
UserService userService = new UserService();
User result = userService.createUser(username, email);
assertEquals(username, result.getUsername());
assertEquals(email, result.getEmail());
}
}
AssertJ - це бібліотека, що дозволяє використовувати зручні та читабельні вирази для перевірки результатів тестів. Ця бібліотека працює з JUnit та TestNG та забезпечує ряд вдосконалень порівняно з класичними методами перевірки:
Припустимо, у вас є клас ShoppingCart, який містить метод getTotal, що повертає загальну вартість товарів у кошику. Ось як можна використати AssertJ для перевірки результату методу:
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class ShoppingCartTest {
@Test
void testGetTotal() {
ShoppingCart shoppingCart = new ShoppingCart();
shoppingCart.addItem(new Item("item1",10.0));
shoppingCart.addItem(new Item("item2", 20.0));
double result = shoppingCart.getTotal();
assertThat(result).isEqualTo(30.0);
}
}
Spring Test - це модуль тестування в рамках Spring Framework, який надає підтримку для юніт- та інтеграційного тестування Spring-додатків. Ось декілька особливостей Spring Test:
Припустимо, у вас є веб-контролер UserController, який обробляє запити на створення користувачів. Ось як можна використати Spring Test для інтеграційного тестування методу створення користувача:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest
@AutoConfigureMockMvc
class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
void testCreateUser() throws Exception {
mockMvc.perform(post("/users")
.param("username", "user1")
.param("email", "email1@example.com"))
.andExpect(status().isCreated());
}
}
Cucumber - це інструмент для тестування поведінки (Behavior-Driven Development, BDD), який дозволяє виконувати тести, написані у природній мові, та перетворювати їх на виконуваний код.
Cucumber співпрацює з JUnit та TestNG та має наступні особливості:
Припустимо, у вас є функціонал "реєстрація користувача" у вашому додатку. Ось як можна написати сценарій Cucumber для тестування цього функціоналу:
Feature: User registration
As a user
I want to register an account
So that I can access the application
Scenario: Successful registration
Given I am on the registration page
When I enter a valid username and email
And I submit the registration form
Then I should be registered and redirected to the home page
Для реалізації кроків сценарію, вам потрібно створити клас з методами, анотованими відповідними анотаціями Cucumber:
import io.cucumber.java.en.Given;
import io.cucumber.java.en.When;
import io.cucumber.java.en.Then;
class UserRegistrationSteps {
@Given("I am on the registration page")
void openRegistrationPage() {
// ...
}
@When("I enter a valid username and email")
void enterValidUserData() {
// ...
}
@When("I submit the registration form")
void submitRegistrationForm() {
// ...
}
@Then("I should be registered and redirected to the home page")
void verifyRegistrationAndRedirection() {
// ...
}
}
Awaitility - це бібліотека для тестування асинхронного коду в Java, яка дозволяє легко перевіряти стан, що змінюється, за допомогою зручного API. Ось декілька особливостей Awaitility:
Припустимо, у вас є асинхронний клас Downloader, який завантажує файли з мережі. Ось як можна використати Awaitility для перевірки завершення завантаження:
import org.junit.jupiter.api.Test;
import static org.awaitility.Awaitility.await;
import static org.awaitility.Duration.*;
import static org.assertj.core.api.Assertions.assertThat;
class DownloaderTest {
@Test
void testDownloadCompletion() {
Downloader downloader = new Downloader();
downloader.downloadFile("https://example.com/file");
await().atMost(FIVE_SECONDS).until(() -> assertThat(downloader.getStatus()).isEqualTo(Downloader.Status.COMPLETED));
}
}
Wiser - це легка бібліотека для тестування електронної пошти в Java-додатках, яка дозволяє перехоплювати електронні листи та перевіряти їх вміст, не надсилаючи їх на справжні поштові сервери.
Ось декілька особливостей Wiser:
Припустимо, у вас є клас EmailService, який відправляє електронні листи користувачам. Ось як можна використати Wiser для тестування відправки електронної пошти:
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.subethamail.wiser.Wiser;
import org.subethamail.wiser.WiserMessage;
import javax.mail.internet.MimeMessage;
import static org.assertj.core.api.Assertions.assertThat;
class EmailServiceTest {
private Wiser wiser;
@BeforeEach
void setUp() {
wiser = new Wiser();
wiser.setPort(2500);
wiser.start();
}
@AfterEach
void tearDown() {
wiser.stop();
}
@Test
void testSendEmail() throws Exception {
EmailService emailService = new EmailService();
emailService.setSmtpHost("localhost");
emailService.setSmtpPort(2500);
emailService.sendEmail("user@example.com", "Test subject", "Test body");
List messages = wiser.getMessages();
assertThat(messages).hasSize(1);
MimeMessage message = messages.get(0).getMimeMessage();
assertThat(message.getSubject()).isEqualTo("Test subject");
assertThat(message.getContent()).isEqualTo("Test body");
}
}
Testcontainers - це бібліотека для інтеграційного тестування Java-додатків, яка дозволяє використовувати Docker-контейнери для створення та керування зовнішніми залежностями, такими як бази даних, кеші, сервіси тощо.
Ось декілька особливостей Testcontainers:
Припустимо, у вас є клас UserRepository, який працює з базою даних PostgreSQL. Ось як можна використати Testcontainers для інтеграційного тестування цього класу:
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import static org.assertj.core.api.Assertions.assertThat;
@Testcontainers
class UserRepositoryTest {
@Container
private static final PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:latest");
@Test
void testFindUserById() throws Exception {
try (Connection connection = DriverManager.getConnection(postgres.getJdbcUrl(), postgres.getUsername(), postgres.getPassword())) {
UserRepository userRepository = new UserRepository(connection);
userRepository.save(new User("John", "Doe"));
User user = userRepository.find(1);
assertThat(user).isNotNull();
assertThat(user.getFirstName()).isEqualTo("John");
assertThat(user.getLastName()).isEqualTo("Doe");
}
}
}
Memoryfilesystem - це бібліотека для створення віртуальних файлових систем у пам'яті для тестування Java-додатків, яка працює зі стандартним API файлів Java (java.nio.file). Ось декілька особливостей Memoryfilesystem:
Припустимо, у вас є клас FileProcessor, який читає файли та обробляє їх вміст. Ось як можна використати Memoryfilesystem для тестування цього класу:
import com.github.marschall.memoryfilesystem.MemoryFileSystemBuilder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.assertj.core.api.Assertions.assertThat;
class FileProcessorTest {
private FileSystem fileSystem;
private FileProcessor fileProcessor;
@BeforeEach
void setUp() {
fileSystem = MemoryFileSystemBuilder.newEmpty().build();
fileProcessor = new FileProcessor();
}
@AfterEach
void tearDown() throws IOException {
fileSystem.close();
}
@Test
void testProcessFile() throws IOException {
Path inputFile = fileSystem.getPath("/input.txt");
Files.write(inputFile, "Hello, World!".getBytes());
Path outputFile = fileSystem.getPath("/output.txt");
fileProcessor.process(inputFile, outputFile);
assertThat(Files.exists(outputFile)).isTrue();
assertThat(Files.readAllLines(outputFile)).containsExactly("Processed: Hello, World!");
}
}
У цій статті ми розглянули десять популярних бібліотек для юніт- та інтеграційного тестування Java-додатків. Кожна з них має свої переваги та особливості, які можуть допомогти вам поліпшити якість тестування та забезпечити надійність вашого коду. Завдяки цим бібліотекам ви зможете створювати більш ефективні тести та забезпечити успішну роботу вашого програмного забезпечення.
У процесі вибору бібліотеки для тестування вашого проекту враховуйте вимоги до функціональності, обсяг проекту та ваші персональні уподобання. Важливо пам'ятати, що якісне тестування - це одна з ключових складових успішного розробництва програмного забезпечення, і відповідний вибір інструментів для тестування може значно полегшити цей процес.