Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Плюсы и минусы AssertJ
AssertJ это современная библиотека для написания читаемых assertion'ов в тестах. Я использую её в 100% своих проектов, и это значительно улучшило качество тестов.
1. Что такое AssertJ
AssertJ предоставляет fluent API для assertion'ов вместо стандартного JUnit:
// Стандартный JUnit (скучно и нечитаемо)
assertTrue(user.getAge() > 18);
assertEquals(user.getName(), "John");
assertNull(user.getEmail());
// AssertJ (читаемо и выразительно)
assertThat(user.getAge())
.isPositive()
.isGreaterThan(18);
assertThat(user.getName())
.isEqualTo("John")
.isNotBlank()
.hasLength(4);
assertThat(user.getEmail())
.isNull();
2. Плюсы AssertJ
1. Читаемость кода:
AssertJ читается как предложение на английском:
// Очень естественно
assertThat(user)
.isNotNull()
.extracting(User::getName)
.isEqualTo("John");
// Vs JUnit (нечитаемо)
assertNotNull(user);
assertEquals(user.getName(), "John");
2. Лучшие error сообщения:
// AssertJ:
List<Integer> actual = Arrays.asList(1, 2, 3);
assertThat(actual).contains(5);
// Сообщение об ошибке:
// Expecting:
// <[1, 2, 3]>
// to contain:
// <[5]>
// but could not find:
// <[5]>
// JUnit:
assertTrue(actual.contains(5));
// Сообщение: "assertion failed"
3. Fluent API (цепочка методов):
assertThat("hello")
.isNotEmpty() // String методы
.hasSize(5)
.startsWith("hel")
.endsWith("lo")
.contains("ll")
.doesNotContain("x");
4. Проверка collections просто:
List<User> users = getUsers();
// Проверить размер
assertThat(users).hasSize(3);
// Проверить наличие элемента
assertThat(users).contains(user1, user2);
// Проверить элементы по условию
assertThat(users)
.filteredOn(u -> u.getAge() > 18)
.hasSize(2);
// Проверить поля
assertThat(users)
.extracting(User::getName)
.contains("John", "Jane");
// Сложные проверки
assertThat(users)
.filteredOn(u -> u.isActive())
.extracting(User::getEmail)
.allMatch(email -> email.contains("@"));
5. Optional и Stream поддержка:
Optional<User> user = findUser();
assertThat(user)
.isPresent()
.hasValue(expectedUser);
assertThat(Optional.empty())
.isEmpty();
Stream<Integer> stream = Stream.of(1, 2, 3);
assertThat(stream).contains(2);
6. Custom assertions легко:
// Можно расширить
public class UserAssertions extends AbstractAssert<UserAssertions, User> {
public UserAssertions isAdult() {
isNotNull();
if (actual.getAge() < 18) {
failWithMessage("User is not an adult");
}
return this;
}
}
// Использование
assertThat(user)
.isNotNull()
.isAdult();
7. Условные assertion'ы (soft assertions):
// Все assertion'ы выполняются, errors собираются
SoftAssertions softly = new SoftAssertions();
softly.assertThat(user.getName()).isEqualTo("Wrong");
softly.assertThat(user.getAge()).isEqualTo(99);
softly.assertThat(user.getEmail()).isNull();
softly.assertAll(); // Выкинет все ошибки разом
// Или более новый стиль
assertThatObject(user)
.satisfies(u -> assertThat(u.getName()).isEqualTo("John"))
.satisfies(u -> assertThat(u.getAge()).isGreaterThan(18));
3. Минусы AssertJ
1. Зависимость добавляется:
<!-- pom.xml -->
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.24.1</version>
<scope>test</scope>
</dependency>
Это не проблема, но добавляет jar в classpath.
2. Кривая обучения:
Способов что-то проверить множество, новички запутаются:
// Много вариантов для одного
assertThat(value).isEqualTo(expected);
assertThat(value).as("value").isEqualTo(expected);
assertThat(value).withFailMessage("Failed").isEqualTo(expected);
3. IDE auto-complete может быть медленным:
Большой fluent API означает много методов, IDE может тормозить.
4. Нетипизированные коллекции сложны:
List raw = getRawList(); // Object list
// Типизировать сложновато
assertThat(raw)
.asInstanceOf(InstanceOfAssertFactories.list(
InstanceOfAssertFactories.type(String.class)))
.contains("value");
5. Нет встроенной поддержки некоторых типов:
Для custom классов нужно писать extractors или assertions.
4. AssertJ vs JUnit
| Аспект | AssertJ | JUnit |
|---|---|---|
| Читаемость | Отличная | Плохая |
| Error сообщения | Детальные | Минимальные |
| API | Fluent | Простой |
| Collections | Мощная | Базовая |
| Типизация | Хорошая | Нет |
| Обучение | Medium | Easy |
5. Best practices AssertJ
1. Используй extracting для вложенных объектов:
List<User> users = getUsers();
assertThat(users)
.extracting(User::getName, User::getAge)
.containsExactly(
tuple("John", 30),
tuple("Jane", 25)
);
2. Используй filteredOn для условных проверок:
assertThat(users)
.filteredOn(u -> u.getAge() > 18)
.as("adults")
.hasSize(5);
3. Описывай what you're testing:
// Хорошо
assertThat(user.getStatus())
.as("user status after payment")
.isEqualTo("PAID");
// Плохо
assertThat(user.getStatus())
.isEqualTo("PAID");
4. Комбинируй assertions логично:
// Хорошо
assertThat(user)
.isNotNull()
.satisfies(u -> {
assertThat(u.getName()).isNotBlank();
assertThat(u.getAge()).isPositive();
});
6. Интеграция с другими библиотеками
AssertJ + Mockito:
Mock<UserRepository> mockRepo = mock(UserRepository.class);
assertThat(mockRepo)
.hasBeenCalledTimes(1)
.with(user);
// Проверка call arguments
assertThat(mockRepo.getUser(userId))
.extracting(User::getName)
.isEqualTo("John");
AssertJ + Spring:
@Test
void testEndpoint() {
var response = webTestClient.get()
.uri("/users/1")
.exchange();
assertThat(response.getStatus())
.isEqualTo(200);
assertThat(response.getBody())
.extracting(User::getName)
.isEqualTo("John");
}
7. Вывод
AssertJ это modern standard для Java тестов. Я рекомендую использовать его везде:
Плюсы перевешивают минусы:
- Тесты более читаемы
- Ошибки более понятны
- Development faster
- Maintenance easier
Минусы минимальны:
- Одна зависимость (не проблема)
- Кривая обучения небольшая
Мой совет: Если в проекте используется JUnit assertions, предложи мигрировать на AssertJ. Это улучшит качество и читаемость всех тестов в проекте. За 10+ лет я вижу что проекты с AssertJ имеют лучшие тесты.