我有一个Springboot
项目,我找到了一种方法来创建和运行简单的Junit
测试用例,该测试用例查看存储库并获取给定实体的一些数据属性。Junit
运行的结果是通过,所以没有问题。
但问题是在这里,我已经看到了很多例子,其中教程展示了Springboot
项目,在这些项目中,他们只需@Runwith
或@SpringBootTest
即可简单地运行Junit
测试 针对其特定的测试类。
就我而言,我必须添加 3 个注释,@SpringBootTest
、@RunWith
以及@ContextConfiguation(with parameters)
,直到我能够运行测试用例。
所以我的问题是我如何能够尽可能简约地运行它,(我看到的一些练习对他们的 springboot 测试类只有一个注释(
我的Springboot
测试类如下所示:
我的 Junit 类的屏幕截图
我的目录结构如下所示:
我的项目目录结构的屏幕截图
我的application.properties
如下所示:
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=none
spring.jpa.hibernate.show-sql=true
spring.datasource.url=jdbc:postgresql://localhost:5432/erfan
spring.datasource.username=erfan
spring.datasource.password=
#Some additional properties is trying to be set by Spring framework so this must be set
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
#spring.datasource.initialization-mode=always
#spring.datasource.initialize=true
#spring.datasource.schema=classpath:/schema.sql
#spring.datasource.continue-on-error=true
#HikariCP is a ConnectionPool manager, related to DB stuff
#Below is the property key you need to set to * as value to expose all kind of monitoring related information
#about your web application
#management.endpoints.web.exposure.include=*
还有我的pom.xml
文件:
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
</parent>
<groupId>com.sample</groupId>
<artifactId>postgres</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>postgres</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</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-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</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-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
那么我的应用程序属性文件中是否缺少某些内容?我应该包含一些东西才能在我的测试类中删除"样板"注释?
取决于你想做什么。 基本上,Spring 具有自定义注释,可将 spring 上下文配置为仅包含相关的 bean。这就是所谓的test slices
.
但是有一些"规则"我总是试图遵循:
- 避免
@SpringBootTest
,除非你正在执行集成测试,或手动设置要使用的类@SpringBootTest(classes = {MyService1.class, MyService2.class}
- 如果你正在测试Spring jpa,你可以使用
@DataJpaTest
注释,示例在这里 - 如果您正在测试控制器,则可以使用
@WebMvcTest
,此处的示例 - 如果要测试其他服务,则始终可以使用
@ContextConfiguration
相应地配置 Spring 上下文。
例如,对于您的测试,我会以以下两种方式之一编写它:
@RunWith(SpringRunner.class)
@DataJpaTest
@Import(AnotherConfig.class)
class MyTest {
// test stuff here
}
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {AnotherConfig.class})
// NOTE, if you have a JpaConfig class where you @EnableJpaRepositories
// you can instead add this config class to the @ContextConfiguration classes
@EnableJpaRepositories
class MyTest {
// test stuff here
}
基本上,不要担心测试上有多少注释,而是担心哪些 bean/服务正在自动连线。例如,@SpringBootTest
是单个注释,但自动连接 Spring 上下文中的所有 bean。
我强烈建议不要在单元测试中使用一堆弹簧注释。单元测试应该只测试一段代码,而不与外部或其他层相关,所以Mockito
就足够了。
例:
@RunWith(MockitoJUnitRunner.class)
public class FooTest {
@InjectMocks
private FooService service;
@Mock
private FooRepository repository;
@Test
public void whenHappyPath_shouldReturnTrue(){
doReturn(Optional.empty()).when(repository).findById(anyLong());
assertTrue(service.isFoo(1L));
}
}
您正在阻止单元测试到达存储库层,因此您无需创建具有嵌入式数据库或任何其他内容的上下文。
如果您用于集成测试,那么它是不同的,您将需要不同的策略。为此,我建议在测试中使用嵌入式数据库(如果您有 h2 依赖项,则默认使用嵌入式数据库(:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
还可以使用integration
或test
弹簧轮廓:
@ActiveProfile("test") // or integration, you choose
public class FooIntegrationTest{
...
}
或强制其他配置文件指向另一个配置
@TestPropertySource(properties = { "spring.config.location=classpath:application-test.yml" })
应用程序测试属性
spring.datasource.url=jdbc:h2:mem:test
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=sa
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create-drop
Erfan,这完全取决于您的测试场景。
第一个场景:完整测试(集成测试(
如果你想测试你的整个应用程序,比如测试服务层、存储库层和控制器层,你需要一个真正的 spring-context,所以你必须使用所有@SpringBootTest
和@RunWith
和......初始化 Spring 上下文以测试整个层。 (这称为集成测试(
单元测试与集成测试:有什么区别
如何使用 Java 集成测试
第二种方案:单元测试
如果你只想测试一段代码,就像你只想测试服务层和其他层(如存储库(在你的场景中并不重要一样,在这种情况下,你必须使用一些新的框架,如Mockito
,来模拟你不想测试它们的部分,在这些场景中你不需要 **spring-context 初始化**,所以你不需要使用@SpringBootTest
或其他注释。
莫皮托样品
因此,根据您的方案,您可以使用这些批注。
我强烈建议您阅读以下链接,了解有关在 Java 中进行测试的最佳实践的更多信息。
Java 测试的现代优秀实践