Test Assertions in Java the best way
Unit testing is a technique to test the smaller pieces of code known as units. A good unit testing has a structure similar to it:
@Test
public void testSomeMethod() {
// Setup
MyClass myClass = new MyClass();
// Execution
int result = myClass.someMethod(2, 3);
// Assertion
assertEquals(5, result, "Expected result is incorrect.");
// Teardown (if necessary)
}
Let's talk about Assertions, and how to create assertions in the best way.
AssertJ
If you are using Java, chances are you are using JUnit 5. JUnit 5 provides many possible assertions, however, it's not very clean. The AssertJ library provides a more fluent way to create assertions.
AssertJ is a Java library to create fluent assertions, and it provides many ways to validate your test.
The fluent API provided by AssertJ makes it easy to read and use.
isEqualTo
The most common usage of AssertJ is to verify if the element is equalTo
another element. We can do it by using the following method:
@org.junit.jupiter.api.Test
void testCalculateEmployeesSumSalary() {
CompanyService companyService = new CompanyService();
Company company = new Company(
List.of(
new Developer("James", BigDecimal.valueOf(5_000)),
new Manager("Jessie", BigDecimal.valueOf(8_000), BigDecimal.valueOf(2_000))
)
);
BigDecimal bigDecimal = companyService.calculateEmployeesSumSalary(company);
org.assertj.core.api.Assertions.assertThat(bigDecimal).isEqualTo(BigDecimal.valueOf(13_000));
}
isRecord
Since Java 16 we have Record in Java, which is an amazing feature. Did you know that it is possible to test whether your class is a record.
You can do it using the isRecord
method.
@Test
void testCompanyType() {
org.assertj.core.api.Assertions.assertThat(Company.class).isRecord();
}
extracting & contains
If you have a list of objects, you can verify if this list contains some elements and also if it does not contain them. Not only that, but you can also extract things from your objects and test only a few elements.
@Test
void testEmployees() {
Company company = new Company(
List.of(
new Developer("James", BigDecimal.valueOf(5_000)),
new Manager("Jessie", BigDecimal.valueOf(8_000), BigDecimal.valueOf(2_000))
)
);
org.assertj.core.api.Assertions.assertThat(company.employees())
.extracting(Employee::getName)
.contains("James", "Jessie")
.doesNotContain("Ash");
}
Testing exceptions
Throwing an exception when a business rule is invalid is very common, but do you know that it is very easy to create a test for it?
We can use the assertThatThrownBy
method.
@Test
void testDeveloperSalary() {
org.assertj.core.api.Assertions
.assertThatThrownBy(() -> new Developer("Brock", BigDecimal.valueOf(800)))
.isInstanceOf(InvalidSalaryException.class)
.hasMessage("The salary should be bigger than the minimum salary (1.000)");
}
SoftAssertions
If you have many assertions, you can also use the SoftAssertions to test all the assertions and give all the results at once.
@Test
void testDeveloperAttributes() {
Developer ashKetchum = new Developer("Ash Ketchum", BigDecimal.valueOf(2_000));
SoftAssertions.assertSoftly(s -> {
s.assertThat(ashKetchum.getSalary()).isEqualTo(BigDecimal.valueOf(2_000));
s.assertThat(ashKetchum.calculateNetSalary()).isEqualByComparingTo(BigDecimal.valueOf(1_500));
s.assertThat(ashKetchum.getName())
.startsWith("Ash")
.endsWith("Ketchum2");
});
}
The output of this execution will be 2 errors
java.lang.AssertionError:
Expected :1500
Actual :1600.0
java.lang.AssertionError:
Expecting actual:
"Ash Ketchum"
to end with:
"Ketchum2"
Conclusion
AssertJ is an awesome library for fluently creating assertions, making it easy to read and use.
If you use another common assertion, please, share it here in the comments.
All the code is available here on my GitHub.