Test Object's multiple properties in Single Assert
JUnit 5, Hamcrest, AssertJ
In this article, we will learn how to assert Object’s multiple properties in a single assert in JUnit 5, Hamcrest, and AssertJ assertion libraries.
Overview
We usually write a unit test to verify the expected output from a piece of code. When the expected output is an Object, there are two ways to verify the properties of an Object:-
- Write an assertion for each property of an object and verify it individually
- Group the assertion for all properties of an object together and verify them collectively
The collective assertion of object properties is more human-readable and maintainable. Let’s see how we can group assertions using JUnit, Hamcrest and AssertJ.
Group the Assertions
Let’s say, we want to verify Product
Object, which has various types of properties, ranging from Long, String, Boolean, Integer, BigDecimal to List.
public class Product {
private Long id;
private String name;
private Boolean onSale;
private Integer stockQuantity;
private BigDecimal price;
private List<String> labels;
}
Junit 5 - assertAll
We can collectively assert the Object’s properties using assertAll()
in Junit 5. Let’s look at the example usage:-
- Verify the value of each Object’s property using
assertEquals()
- Verify the various Object’s property conditions using
assertNotNull()
andassertTrue()
assertAll(messge,
() -> assertFn(expected, actual),
() -> assertFn(...),
() -> assertFn(...)
)
import static org.junit.jupiter.api.Assertions.*;
@Test
public void givenObject_testAllProperties() {
// Object to test
Product product = new Product(1L, "Office Desk", true, 50, new BigDecimal("599.99"), Arrays.asList("Wooden", "Electric"));
// 1. Verify property values collectively
assertAll("Verify All Product Property Values",
() -> assertEquals(1L, product.getId()),
() -> assertEquals("Office Desk", product.getName()),
() -> assertEquals(true, product.getOnSale()),
() -> assertEquals(50, product.getStockQuantity()),
() -> assertEquals("599.99", product.getPrice().toString()),
() -> assertEquals(Arrays.asList("Wooden", "Electric"), product.getLabels()));
// 2. Test property conditions collectively
assertAll("Verify Product Property Conditions",
() -> assertNotNull(product),
() -> assertNotNull(product.getId()),
() -> assertTrue(product.getName().contains("Desk")), // Product name contains 'Desk'
() -> assertTrue(product.getOnSale()), // Product on sale
() -> assertTrue(product.getStockQuantity() > 0), // Stock is available
() -> assertTrue(product.getPrice().compareTo(new BigDecimal(1000.0)) < 0), // Price under 1000
() -> assertTrue(product.getLabels().contains("Wooden"))); // Looking for 'Wooden' Desk
}
Hamcrest - allOf
We can combine the Hamcrest matchers using allOf()
to collectively assert the Object’s properties.
assertThat(message, object, allOf(matcher1, matcher2, ...))
Let’s look a the example usage:-
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
@Test
public void givenObject_testAllProperties() {
// Object to test
Product product = new Product(1L, "Office Desk", true, 50, new BigDecimal("599.99"), Arrays.asList("Wooden", "Electric"));
// Verify property values collectively
assertThat("Verify All Product Property Values", product, allOf(
hasProperty("id", equalTo(1L)),
hasProperty("name", equalTo("Office Desk")),
hasProperty("onSale", is(true)),
hasProperty("stockQuantity", equalTo(50)),
hasProperty("price", is(new BigDecimal("599.99"))),
hasProperty("labels", equalTo(List.of("Wooden", "Electric")))));
// Test property conditions collectively
assertThat("Verify Product Property Conditions", product, allOf(
notNullValue(),
hasProperty("id", notNullValue()),
hasProperty("name", endsWith("Desk")), // Product name endsWith 'Desk'
hasProperty("onSale", is(true)), // Product on sale
hasProperty("stockQuantity", greaterThan(0)), // Stock is available
hasProperty("price", lessThan(new BigDecimal(1000.0))), // Price under 1000
hasProperty("labels", hasItem("Electric")))); // Looking for 'Electric' Desk
}
AssertJ - extracting..containsExactly
In AssertJ, we can collectively assert the Object’s properties by extracting them as a List using extracting()
and then chain them with containsExactly()
to verify the:-
- value of each Object’s property extracted from
extracting()
by passing field names - result of each Object’s property condition extracted from
extracting()
by passing conditions
assertThat(object)
.describedAs(message)
.extracting(fieldName1/condition1, fieldName2/condition2, ...)
.containsExactly(value1/result1, value2/result2, ...)
Let’s look at the example usage:-
import static org.assertj.core.api.Assertions.*;
@Test
public void givenObject_testAllProperties_extracting_containsExactly(){
// Object to test
Product product = new Product(1L, "Office Desk", true, 50, new BigDecimal("599.99"), Arrays.asList("Wooden", "Electric"));
// 1. Verify property values collectively
assertThat(product)
.describedAs("Verify All Product Property Values")
.extracting("id", "name", "onSale", "stockQuantity", "price", "labels")
.containsExactly(1L, "Office Desk", true, 50, new BigDecimal("599.99"), Arrays.asList("Wooden", "Electric"));
// 2. Test property conditions collectively
assertThat(product)
.describedAs("Verify Product Property Conditions")
.extracting(Product::getId,
Product::getName,
Product::getOnSale,
p -> p.getStockQuantity() > 0,
p -> p.getPrice().compareTo(new BigDecimal(1000.0)) < 0,
p -> p.getLabels().contains("Wooden"))
.containsExactly(1L, "Office Desk", true, true, true, true);
}
AssertJ - returns..from
In AssertJ, we can collectively assert the Object’s property by chaining the returns()
for each property together. We extract the:-
- value from Object’s property by passing the field name in
from()
- result from Object’s property condition by passing the condition in
from()
assertThat(object)
.describedAs(message)
.returns(expected, from(fieldNameOrCondition))
.returns(...)
.returns(...)
Let’s look at the example usage:-
import static org.assertj.core.api.Assertions.*;
@Test
public void givenObject_testAllProperties_returns_from(){
// Object to test
Product product = new Product(1L, "Office Desk", true, 50, new BigDecimal("599.99"), Arrays.asList("Wooden", "Electric"));
// 1. Verify property values collectively
assertThat(product)
.describedAs("Verify All Product Property Values")
.returns(1L, from(Product::getId))
.returns("Office Desk", from(Product::getName))
.returns(true, from(Product::getOnSale))
.returns(50, from(Product::getStockQuantity))
.returns(new BigDecimal("599.99"), from(Product::getPrice))
.returns(Arrays.asList("Wooden", "Electric"), from(Product::getLabels));
// 2. Test property conditions collectively
assertThat(product)
.describedAs("Verify Product Property Conditions")
.isNotNull()
.hasNoNullFieldsOrProperties()
.returns(true, from(p -> p.getName().contains("Desk"))) // Product name endsWith 'Desk'
.returns(true, from(Product::getOnSale)) // Product on sale
.returns(true, from(p -> p.getStockQuantity() > 0)) // Stock is available
.returns(true, from(p -> p.getPrice().compareTo(new BigDecimal(1000.0)) < 0)) // Price under 1000
.returns(true, from(p -> p.getLabels().contains("Wooden"))); // Looking for 'Wooden' Desk
}