I have two tests files in project. One is testing directly my persistence layer :
@RunWith(SpringRunner.class)
@DataJpaTest
public class UserTests {
@Autowired
private TestEntityManager entityManager;
@Autowired
private UserRepository repository;
@Test
public void whenFindByEmail_thenReturnUser() {
// given
User user = new User("email@email.com", "12345678", "Some Name");
entityManager.persist(user);
entityManager.flush();
// when
User found = repository.findByEmail(user.getEmail());
// then
assertThat(found.getName()).isEqualTo(user.getName());
assertThat(found.getEmail()).isEqualTo(user.getEmail());
assertThat(found.getPasswordHash()).isEqualTo(user.getPasswordHash());
}
}
The other one is testing a service using the persistence layer :
@RunWith(SpringRunner.class)
@DataJpaTest
public class UserServiceTests {
@Autowired
private UserService service;
@Test
public void testSuccessfullUserCreation() {
UserCreationResult res = service.createUser("anything@anything.com", "1234567890", "Test");
assertThat(res).isEqualTo(UserCreationResult.OK);
}
@Test
public void testWrongEmailUserCreation() {
UserCreationResult res = service.createUser("anything@anything", "1234567890", "Test");
assertThat(res).isEqualTo(UserCreationResult.INVALID_EMAIL);
}
@Test
public void testTooShortPasswordUserCreation() {
String shortPassword =
String.join("", Collections.nCopies(UserService.minPasswordLength - 1, "0"));
UserCreationResult res = service.createUser("anything@anything.com", shortPassword, "Test");
assertThat(res).isEqualTo(UserCreationResult.WRONG_PASSWORD_LENGTH);
}
@Test
public void testTooLongPasswordUserCreation() {
String longPassword =
String.join("", Collections.nCopies(UserService.maxPasswordLength + 1, "0"));
UserCreationResult res = service.createUser("anything@anything.com", longPassword, "Test");
assertThat(res).isEqualTo(UserCreationResult.WRONG_PASSWORD_LENGTH);
}
@Test
public void testMaxLengthPasswordUserCreation() {
String maxPassword =
String.join("", Collections.nCopies(UserService.maxPasswordLength, "0"));
UserCreationResult res = service.createUser("anything@anything.com", maxPassword, "Test");
assertThat(res).isEqualTo(UserCreationResult.OK);
}
@Test
public void testMinLengthPasswordUserCreation() {
String minPassword =
String.join("", Collections.nCopies(UserService.minPasswordLength, "0"));
UserCreationResult res = service.createUser("anything@anything.com", minPassword, "Test");
assertThat(res).isEqualTo(UserCreationResult.OK);
}
@Test
public void testReservedEmailUserCreation() {
String email = "email@email.com";
UserCreationResult res = service.createUser(email, "1234567890", "Test");
assertThat(res).isEqualTo(UserCreationResult.OK);
res = service.createUser(email, "1234567890", "Test");
assertThat(res).isEqualTo(UserCreationResult.RESERVED_EMAIL);
}
}
First, my service autowiring wasn't working (UnsatisfiedDependencyException
) so I had to add :
@ComponentScan("my.service.package")
annotation to the test class.
This made the tests of UserServiceTests
work when they were run independently (using eclipse to run only this class).
But when running all the tests of my app (in eclipse or with a good old mvn clean test
), I had the same error on the same test class.
I tried adding the same component scan annotation to the other test class (UserTests
) then everything worked.
I removed the component scan annotation from UserServiceTests
and it still works.
I obviously deduced that the order the tests are executed matters.
Here are my 3 questions, the real one being the last one :
- In the first place why do I have to put this component scan annotation even if my class is properly annotated
@Service
(so should be detected as a bean) ? - How is it that the order of tests matters ?
- How can I have multiple JPA tests files that would run with a proper dependency injection independently ?
Here is my service class :
@Service
public class UserService {
@Autowired
private UserRepository repository;
public static final int minPasswordLength = 8;
public static final int maxPasswordLength = 50;
public static enum UserCreationResult {
OK, INVALID_EMAIL, RESERVED_EMAIL, WRONG_PASSWORD_LENGTH, UNKNOWN_ERROR
}
@Transactional
public UserCreationResult createUser(String email, String password, String name) {
if (password.length() < minPasswordLength || password.length() > maxPasswordLength) {
return UserCreationResult.WRONG_PASSWORD_LENGTH;
}
if (!EmailValidator.getInstance().isValid(email)) {
return UserCreationResult.INVALID_EMAIL;
}
final User existingUser = repository.findByEmail(email);
if (existingUser != null) {
return UserCreationResult.RESERVED_EMAIL;
}
final User user = repository.save(new User(email, password, name));
return user == null ? UserCreationResult.UNKNOWN_ERROR : UserCreationResult.OK;
}
}
And there is my pom.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.somedomain</groupId>
<artifactId>ws-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>My App</name>
<description>My app's description</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>