Spring 启动测试不启动上下文或加载依赖项
Spring Boot test does not start context or load dependencies
一个非常初学者的问题,但我无法通过。我有一个基本的 Spring 引导应用程序,以及一个连接到云图集实例的 Spring 数据 MongoDB 存储库。问题是在我的 Spring 引导测试中,我的存储库没有自动装配并且没有创建嵌入式 MongoDB 实例。如果我启动 Spring Boot 应用程序并在主要 class 中自动装配存储库,那就行得通了。为什么它在我的测试中不起作用?
这是我的测试class:
@DataMongoTest
@ExtendWith(SpringExtension.class)
public class SampleServiceTest{
@Autowired
private SampleRepository sampleRepository;
@Test
public void shouldCreateSample(){
sampleRepository.save(new Sample());
}
}
这是我的 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">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath></relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.comand</groupId>
<artifactId>business-owner-service</artifactId>
<version>1.0-SNAPSHOT</version>
<description>API Gateway</description>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
当您使用 @Autowired
注释时,基本上您是将变量映射到应用程序上下文中存在的对象。请记住,应用程序上下文是在您启动 spring 引导应用程序时创建的。所有具有注释 @Service
、@Repository
、@Component
的 classes 都在应用程序上下文中实例化。
我假设 SampleRepository
具有以下注释之一:@Service
、@Repository
、@Component
@Repository
。当您启动 spring 引导应用程序时,应用程序上下文已创建并已实例化 SampleRepository
class.
@Autowire
注释会将在应用程序上下文中创建的对象映射到具有注释 @Autowire
.
的变量
它在您的测试中不起作用的原因是 SampleRepository
class 的对象不存在。而且你不能将它映射到你用 @Autowire
.
注释的变量
您可以通过两种方式解决此问题:
- 第一个解决方案是在 运行 测试 class 时创建应用程序上下文。我建议不要加载所有实例化对象的整个应用程序上下文。最好只加载测试中需要的应用程序上下文部分 class。
@EnableConfigurationProperties(SampleRepository.class)
public class TestConfiguration {
}
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = { TestConfiguration.class })
public class SampleServiceTest{
}
- 第二种解决方案是修改注解
@DataMongoTest
,如下所示:
@DataMongoTest(includeFilters = @Filter(Service.class))
//or
@DataMongoTest(includeFilters = @Filter(Component.class))
使用 @DataMongoTest
注释将禁用完全自动配置,而是仅应用与 MongoDB 测试相关的配置。所以用@Services
,Component
注解的classes没有被实例化。 includeFilters
是一组过滤器,可用于将过滤的 bean 添加到应用程序上下文。
我怀疑您用 @Service
或 @Component
注释对 class SampleRepository
进行了注释,这就是为什么它没有创建 [=18= 的实例的原因] class.
我在 git repo 中查看了您的代码,并修改如下:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class BusinessOwnerServiceTest {
@Autowired
private BusinessOwnerService businessOwnerService;
@Autowired
private BusinessOwnerRepository businessOwnerRepository;
@Test
public void shouldCreateNewBusinessOwner(){
businessOwnerService.findBusinessOwnerByEmail("EMAIL@gmail.com");
}
}
下面是结果:
下面是第二种解法:
@RunWith(SpringJUnit4ClassRunner.class)
@DataMongoTest(includeFilters = @Filter(Service.class))
public class BusinessOwnerServiceTest {
@Autowired
private BusinessOwnerService businessOwnerService;
@Autowired
private BusinessOwnerRepository businessOwnerRepository;
@Test
public void shouldCreateNewBusinessOwner(){
businessOwnerService.findBusinessOwnerByEmail("EMAIL@gmail.com");
}
}
下面是第二种解决方案的结果:
一个非常初学者的问题,但我无法通过。我有一个基本的 Spring 引导应用程序,以及一个连接到云图集实例的 Spring 数据 MongoDB 存储库。问题是在我的 Spring 引导测试中,我的存储库没有自动装配并且没有创建嵌入式 MongoDB 实例。如果我启动 Spring Boot 应用程序并在主要 class 中自动装配存储库,那就行得通了。为什么它在我的测试中不起作用?
这是我的测试class:
@DataMongoTest
@ExtendWith(SpringExtension.class)
public class SampleServiceTest{
@Autowired
private SampleRepository sampleRepository;
@Test
public void shouldCreateSample(){
sampleRepository.save(new Sample());
}
}
这是我的 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">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath></relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.comand</groupId>
<artifactId>business-owner-service</artifactId>
<version>1.0-SNAPSHOT</version>
<description>API Gateway</description>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
当您使用 @Autowired
注释时,基本上您是将变量映射到应用程序上下文中存在的对象。请记住,应用程序上下文是在您启动 spring 引导应用程序时创建的。所有具有注释 @Service
、@Repository
、@Component
的 classes 都在应用程序上下文中实例化。
我假设 SampleRepository
具有以下注释之一:@Service
、@Repository
、@Component
@Repository
。当您启动 spring 引导应用程序时,应用程序上下文已创建并已实例化 SampleRepository
class.
@Autowire
注释会将在应用程序上下文中创建的对象映射到具有注释 @Autowire
.
它在您的测试中不起作用的原因是 SampleRepository
class 的对象不存在。而且你不能将它映射到你用 @Autowire
.
您可以通过两种方式解决此问题:
- 第一个解决方案是在 运行 测试 class 时创建应用程序上下文。我建议不要加载所有实例化对象的整个应用程序上下文。最好只加载测试中需要的应用程序上下文部分 class。
@EnableConfigurationProperties(SampleRepository.class)
public class TestConfiguration {
}
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = { TestConfiguration.class })
public class SampleServiceTest{
}
- 第二种解决方案是修改注解
@DataMongoTest
,如下所示:
@DataMongoTest(includeFilters = @Filter(Service.class))
//or
@DataMongoTest(includeFilters = @Filter(Component.class))
使用 @DataMongoTest
注释将禁用完全自动配置,而是仅应用与 MongoDB 测试相关的配置。所以用@Services
,Component
注解的classes没有被实例化。 includeFilters
是一组过滤器,可用于将过滤的 bean 添加到应用程序上下文。
我怀疑您用 @Service
或 @Component
注释对 class SampleRepository
进行了注释,这就是为什么它没有创建 [=18= 的实例的原因] class.
我在 git repo 中查看了您的代码,并修改如下:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class BusinessOwnerServiceTest {
@Autowired
private BusinessOwnerService businessOwnerService;
@Autowired
private BusinessOwnerRepository businessOwnerRepository;
@Test
public void shouldCreateNewBusinessOwner(){
businessOwnerService.findBusinessOwnerByEmail("EMAIL@gmail.com");
}
}
下面是结果:
下面是第二种解法:
@RunWith(SpringJUnit4ClassRunner.class)
@DataMongoTest(includeFilters = @Filter(Service.class))
public class BusinessOwnerServiceTest {
@Autowired
private BusinessOwnerService businessOwnerService;
@Autowired
private BusinessOwnerRepository businessOwnerRepository;
@Test
public void shouldCreateNewBusinessOwner(){
businessOwnerService.findBusinessOwnerByEmail("EMAIL@gmail.com");
}
}
下面是第二种解决方案的结果: