Fluent assertion library providing rich assertions for Java tests with expressive failure messages
—
Custom conditions and condition combinators for reusable and composable assertions that can be applied to any object type.
import static org.assertj.core.api.Assertions.*;
import org.assertj.core.api.Condition;Define reusable conditions for complex validation logic.
// Condition interface
interface Condition<T> {
boolean matches(T value)
String description()
}
// Creating conditions
static <T> Condition<T> condition(Predicate<T> predicate, String description)
static <T> Condition<T> condition(Predicate<T> predicate, String description, Object... args)
// Constructor-based condition creation
class Condition<T> {
Condition(Predicate<T> predicate, String description)
Condition(String description, Predicate<T> predicate) // deprecated order
}Usage examples:
// Simple custom conditions
Condition<String> notBlank = new Condition<>(
s -> s != null && !s.trim().isEmpty(),
"not blank"
);
Condition<Integer> positive = new Condition<>(
n -> n > 0,
"positive number"
);
Condition<User> adult = new Condition<>(
user -> user.getAge() >= 18,
"adult user"
);
// Using conditions in assertions
assertThat("Hello").is(notBlank);
assertThat(42).satisfies(positive);
assertThat(user).has(adult);Combine multiple conditions using logical operators.
// Logical combinators
static <T> Condition<T> allOf(Condition<? super T>... conditions)
static <T> Condition<T> allOf(Iterable<? extends Condition<? super T>> conditions)
static <T> Condition<T> anyOf(Condition<? super T>... conditions)
static <T> Condition<T> anyOf(Iterable<? extends Condition<? super T>> conditions)
static <T> Condition<T> not(Condition<? super T> condition)
// Condition chaining methods
Condition<T> and(Condition<? super T> other)
Condition<T> or(Condition<? super T> other)Usage examples:
// Define individual conditions
Condition<String> notNull = new Condition<>(Objects::nonNull, "not null");
Condition<String> notEmpty = new Condition<>(s -> !s.isEmpty(), "not empty");
Condition<String> hasLength = new Condition<>(s -> s.length() > 5, "length > 5");
// Combine conditions
Condition<String> validString = allOf(notNull, notEmpty, hasLength);
Condition<String> someValid = anyOf(notEmpty, hasLength);
Condition<String> invalid = not(validString);
// Use combined conditions
assertThat("Hello World").is(validString);
assertThat("Hi").is(someValid);
assertThat("").is(invalid);
// Chaining approach
Condition<Integer> validAge = positive.and(
new Condition<>(age -> age <= 150, "reasonable age")
);
assertThat(25).satisfies(validAge);Apply conditions to assertions using various methods.
// Condition assertion methods
ObjectAssert<T> is(Condition<? super T> condition)
ObjectAssert<T> isNot(Condition<? super T> condition)
ObjectAssert<T> has(Condition<? super T> condition)
ObjectAssert<T> doesNotHave(Condition<? super T> condition)
ObjectAssert<T> satisfies(Condition<? super T> condition)
ObjectAssert<T> satisfiesAnyOf(Condition<? super T>... conditions)
// Collection condition methods
IterableAssert<T> are(Condition<? super T> condition)
IterableAssert<T> areNot(Condition<? super T> condition)
IterableAssert<T> have(Condition<? super T> condition)
IterableAssert<T> doNotHave(Condition<? super T> condition)
IterableAssert<T> areAtLeast(int times, Condition<? super T> condition)
IterableAssert<T> areAtMost(int times, Condition<? super T> condition)
IterableAssert<T> areExactly(int times, Condition<? super T> condition)
IterableAssert<T> haveAtLeast(int times, Condition<? super T> condition)
IterableAssert<T> haveAtMost(int times, Condition<? super T> condition)
IterableAssert<T> haveExactly(int times, Condition<? super T> condition)Usage examples:
// Single object conditions
User user = new User("Alice", 30, "alice@domain.com");
assertThat(user).is(adult);
assertThat(user).has(validEmail);
assertThat(user).satisfies(allOf(adult, validEmail));
// Collection conditions
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
assertThat(numbers).are(positive);
assertThat(numbers).haveAtLeast(3, new Condition<>(n -> n > 2, "> 2"));
assertThat(numbers).areExactly(2, new Condition<>(n -> n % 2 == 0, "even"));
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Condition<String> shortName = new Condition<>(s -> s.length() <= 5, "short name");
assertThat(names).areAtMost(2, shortName);Common conditions provided by AssertJ.
// Predefined condition factories
static <T> Condition<T> matching(Predicate<T> predicate, String description)
static <T> Condition<T> not(Condition<? super T> condition)
// Collection-specific conditions
static <T> Condition<Iterable<? extends T>> hasSize(int expectedSize)
static <T> Condition<T[]> hasSize(int expectedSize)Usage examples:
// Using predefined conditions
List<String> items = Arrays.asList("one", "two", "three");
assertThat(items).has(hasSize(3));
assertThat(new String[]{"a", "b"}).has(hasSize(2));Complex condition scenarios and patterns.
// Condition composition
static <T> Condition<T> describedAs(String description, Condition<T> condition)
// Verbose conditions with detailed error messages
class VerboseCondition<T> extends Condition<T> {
VerboseCondition(Predicate<T> predicate, String description)
}Usage examples:
// Domain-specific conditions
Condition<Order> validOrder = new Condition<>(order ->
order != null &&
order.getCustomer() != null &&
!order.getItems().isEmpty() &&
order.getTotal().compareTo(BigDecimal.ZERO) > 0,
"valid order"
);
Condition<Product> inStock = new Condition<>(product ->
product.getQuantity() > 0,
"in stock"
);
Condition<Product> affordable = new Condition<>(product ->
product.getPrice().compareTo(new BigDecimal("100")) <= 0,
"affordable (≤ $100)"
);
// Complex business rules
Condition<Order> eligibleForDiscount = allOf(
validOrder,
new Condition<>(order -> order.getTotal().compareTo(new BigDecimal("50")) >= 0, "minimum $50"),
new Condition<>(order -> order.getCustomer().isPremium(), "premium customer")
);
assertThat(order).satisfies(eligibleForDiscount);
// Collection with complex conditions
List<Product> products = getProducts();
assertThat(products)
.haveAtLeast(5, inStock)
.haveAtMost(10, affordable)
.areNot(new Condition<>(Product::isDiscontinued, "discontinued"));Customizing condition error messages and descriptions.
// Custom error message formatting
Condition<T> describedAs(String description)
Condition<T> as(String description)
// Error message with parameters
static <T> Condition<T> condition(Predicate<T> predicate, String description, Object... args)Usage examples:
// Descriptive conditions with context
Condition<String> validUsername = new Condition<>(
username -> username.matches("[a-zA-Z0-9_]{3,20}"),
"valid username (3-20 alphanumeric characters or underscore)"
);
Condition<Integer> inRange = new Condition<>(
value -> value >= 1 && value <= 100,
"in range [1, 100]"
);
// Parameterized descriptions
Condition<String> hasMinLength(int minLength) {
return new Condition<>(
s -> s.length() >= minLength,
"has minimum length of %d characters",
minLength
);
}
// Usage with better error messages
assertThat("ab").satisfies(hasMinLength(3));
// Error: Expecting <"ab"> to satisfy: <has minimum length of 3 characters>
assertThat("user!").satisfies(validUsername);
// Error: Expecting <"user!"> to satisfy: <valid username (3-20 alphanumeric characters or underscore)>Utility methods for working with conditions.
// Condition testing
boolean matches(T value)
String description()
// Condition factories for common scenarios
static <T> Condition<T> anyOf(Collection<? extends Condition<? super T>> conditions)
static <T> Condition<T> allOf(Collection<? extends Condition<? super T>> conditions)Usage examples:
// Testing conditions directly
Condition<String> emailFormat = new Condition<>(
email -> email.contains("@") && email.contains("."),
"valid email format"
);
String testEmail = "user@domain.com";
boolean isValid = emailFormat.matches(testEmail);
System.out.println("Email valid: " + isValid);
System.out.println("Condition: " + emailFormat.description());
// Building condition collections
List<Condition<User>> userValidations = Arrays.asList(
new Condition<>(u -> u.getName() != null, "has name"),
new Condition<>(u -> u.getAge() >= 0, "non-negative age"),
new Condition<>(u -> u.getEmail().contains("@"), "valid email")
);
Condition<User> allUserValidations = allOf(userValidations);
assertThat(user).satisfies(allUserValidations);
// Conditional validation based on type
Condition<Object> typeSpecific = new Condition<>(obj -> {
if (obj instanceof String) {
return !((String) obj).isEmpty();
} else if (obj instanceof Number) {
return ((Number) obj).doubleValue() >= 0;
}
return true;
}, "type-specific validation");// Core condition interface
interface Condition<T> {
boolean matches(T value);
String description();
// Default combination methods
default Condition<T> and(Condition<? super T> other) {
return allOf(this, other);
}
default Condition<T> or(Condition<? super T> other) {
return anyOf(this, other);
}
}
// Predicate interface for condition logic
interface Predicate<T> {
boolean test(T t);
// Default combination methods
default Predicate<T> and(Predicate<? super T> other);
default Predicate<T> or(Predicate<? super T> other);
default Predicate<T> negate();
}
// Condition implementation classes
abstract class Join<T> extends Condition<T> {
// Base class for condition combinators
}
class AllOf<T> extends Join<T> {
// AND combination of conditions
}
class AnyOf<T> extends Join<T> {
// OR combination of conditions
}
class Not<T> extends Condition<T> {
// Negation of a condition
}
class VerboseCondition<T> extends Condition<T> {
// Condition with enhanced error reporting
}Install with Tessl CLI
npx tessl i tessl/maven-org-assertj--assertj-core