Test code readability improved: JUnit with Mockito and FEST Fluent Assertions
To improve the readability of my unit tests I use assertThat with Hamcrest matchers. This is a good way to improve readability of your test code, especially when I statically import members of like org.junit.Assert.assertThat and org.hamcrest.Matchers. But when I add Mockito matchers on top of it, I experienced the problem of static import conflicts that ended up with "not nice" code (according to my definition).
Let's look at the (hypothetical) example:
Then, some time ago, someone mentioned on Twitter that I should try FEST Fluent Assertions. So I gave it a try and I ended up with the below:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {
@InjectMocks
private UserService userService = new UserService();
@Mock
private UserRepository userRepositoryMock;
@Test
public void returnsUserDetailsFoundInRepository() {
// arrange
User demoUser = new User("user", "demo", "ROLE_USER");
when(userRepositoryMock.findByUsername("user")).thenReturn(demoUser);
// act
User userDetails = userService.loadUserByUsername("user");
// assert
assertThat(userDetails.getUsername(), org.hamcrest.Matchers.startsWith("user"));
verify(userRepositoryMock).findByUsername(org.mockito.Matchers.startsWith("user"));
}
}
In the assert section I must choose to statically import either org.hamcrest.Matchers.startsWith or org.mockito.Matchers.startsWith. And I don't really like it.
Then, some time ago, someone mentioned on Twitter that I should try FEST Fluent Assertions. So I gave it a try and I ended up with the below:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Matchers.startsWith;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {
@InjectMocks
private UserService userService = new UserService();
@Mock
private UserRepository userRepositoryMock;
@Test
public void returnsUserDetailsFoundInRepository() {
// arrange
User demoUser = new User("user", "demo", "ROLE_USER");
when(userRepositoryMock.findByUsername("user")).thenReturn(demoUser);
// act
User userDetails = userService.loadUserByUsername("user");
// assert
assertThat(userDetails.getUsername()).startsWith("user");
verify(userRepositoryMock).findByUsername(startsWith("user"));
}
}
The changes are:
-
import static org.fest.assertions.Assertions.assertThat instead of import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.startsWith;
@Test
public void returnsMostActiveUsers() {
List users = userService.getMostActiveUsers();
assertThat(users)
.hasSize(3)
.containsOnly(userWith10Activities, userWith5Activities);
}
To have all libraries available with Maven the following dependencies should be used:
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit-dep</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert</artifactId>
<version>1.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
<version>1.3</version>
</dependency>
All of the above you can find on Github: Unit Testing Demo and in Spring MVC Quickstart Archetype.