我的项目中有两个测试文件。 一种是直接测试我的持久层:
@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("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b5d0d8d4dcd9f5d0d8d4dcd99bd6dad8" rel="noreferrer noopener nofollow">[email protected]</a>", "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());
}
}
另一个是使用持久层测试服务:
@RunWith(SpringRunner.class)
@DataJpaTest
public class UserServiceTests {
@Autowired
private UserService service;
@Test
public void testSuccessfullUserCreation() {
UserCreationResult res = service.createUser("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="63020d1a170b0a0d0423020d1a170b0a0d044d000c0e" rel="noreferrer noopener nofollow">[email protected]</a>", "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("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3f5e51464b575651587f5e51464b57565158115c5052" rel="noreferrer noopener nofollow">[email protected]</a>", 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("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="25444b5c514d4c4b4265444b5c514d4c4b420b464a48" rel="noreferrer noopener nofollow">[email protected]</a>", 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("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3d5c5344495554535a7d5c5344495554535a135e5250" rel="noreferrer noopener nofollow">[email protected]</a>", maxPassword, "Test");
assertThat(res).isEqualTo(UserCreationResult.OK);
}
@Test
public void testMinLengthPasswordUserCreation() {
String minPassword =
String.join("", Collections.nCopies(UserService.minPasswordLength, "0"));
UserCreationResult res = service.createUser("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="65040b1c110d0c0b0225040b1c110d0c0b024b060a08" rel="noreferrer noopener nofollow">[email protected]</a>", minPassword, "Test");
assertThat(res).isEqualTo(UserCreationResult.OK);
}
@Test
public void testReservedEmailUserCreation() {
String email = "<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6a0f070b03062a0f070b030644090507" rel="noreferrer noopener nofollow">[email protected]</a>";
UserCreationResult res = service.createUser(email, "1234567890", "Test");
assertThat(res).isEqualTo(UserCreationResult.OK);
res = service.createUser(email, "1234567890", "Test");
assertThat(res).isEqualTo(UserCreationResult.RESERVED_EMAIL);
}
}
首先,我的服务 Autowiring 不起作用(UnsatisfiedDependencyException
),所以我必须添加:
测试类的 @ComponentScan("my.service.package")
注释。
这使得 UserServiceTests
的测试在独立运行时可以工作(使用 eclipse 仅运行此类)。
但是当运行我的应用程序的所有测试时(在 Eclipse 中或使用旧的 mvn clean test
),我在同一个测试类上遇到了相同的错误。
我尝试将相同的组件扫描注释添加到其他测试类 (UserTests
),然后一切正常。
我从 UserServiceTests
中删除了组件扫描注释,它仍然有效。
我显然推断出测试执行的顺序很重要。
这是我的 3 个问题,真正的问题是最后一个:
- 首先,即使我的类已正确注释
@Service
(因此应该被检测为 bean),为什么我必须添加此组件扫描注释? - 测试顺序有何影响?
- 如何拥有多个可以通过正确的依赖项注入(inject)独立运行的 JPA 测试文件?
这是我的服务类别:
@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;
}
}
这是我的 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>
最佳答案
多亏了 question and answer,我才能够通过正确的配置进行测试。
在我的 UserServiceTests
中,服务基本上没有 Autowiring ,因为这是 @DataJpaTest
的预期行为:它不扫描常规 bean。
所以我在这个类中使用了@SpringBootTest
,并删除了两个测试类中的组件扫描。
之后,我的一些服务测试失败了,因为使用 @SpringBootTest
时,每次测试后数据库都不会重置。
我在每次服务测试后添加了一个简单的存储库清理,一切正常。
这个问题仍然存在:
How is it that the order of tests matters ?
这是我的新测试类(class):
服务测试:
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTests {
@Autowired
private UserService service;
@Autowired
private UserRepository repository;
@After
public void cleanUsers() {
repository.deleteAll();
}
@Test
public void testSuccessfullUserCreation() {
UserCreationResult res = service.createUser("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="aacbc4d3dec2c3c4cdeacbc4d3dec2c3c4cd84c9c5c7" rel="noreferrer noopener nofollow">[email protected]</a>", "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("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="99f8f7e0edf1f0f7fed9f8f7e0edf1f0f7feb7faf6f4" rel="noreferrer noopener nofollow">[email protected]</a>", 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("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e5848b9c918d8c8b82a5848b9c918d8c8b82cb868a88" rel="noreferrer noopener nofollow">[email protected]</a>", 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("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2e4f40575a464740496e4f40575a46474049004d4143" rel="noreferrer noopener nofollow">[email protected]</a>", maxPassword, "Test");
assertThat(res).isEqualTo(UserCreationResult.OK);
}
@Test
public void testMinLengthPasswordUserCreation() {
String minPassword =
String.join("", Collections.nCopies(UserService.minPasswordLength, "0"));
UserCreationResult res = service.createUser("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="bfded1c6cbd7d6d1d8ffded1c6cbd7d6d1d891dcd0d2" rel="noreferrer noopener nofollow">[email protected]</a>", minPassword, "Test");
assertThat(res).isEqualTo(UserCreationResult.OK);
}
@Test
public void testReservedEmailUserCreation() {
String email = "<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5e3b333f37321e3b333f3732703d3133" rel="noreferrer noopener nofollow">[email protected]</a>";
UserCreationResult res = service.createUser(email, "1234567890", "Test");
assertThat(res).isEqualTo(UserCreationResult.OK);
res = service.createUser(email, "1234567890", "Test");
assertThat(res).isEqualTo(UserCreationResult.RESERVED_EMAIL);
}
}
JPA 测试:
@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("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="314442544371444254431f525e5c" rel="noreferrer noopener nofollow">[email protected]</a>", "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());
}
}
关于Spring Boot 5 多个 JUnit JPA 测试文件接线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48362072/