使用内存中数据库为 Rest 控制器编写测试



我正在为Spring boot Rest控制器编写一个测试。此 rest 控制器将一些值写入数据库。

我想使用Spring为此测试提供的内存数据库。根据这个文档,我必须用@DataJpaTest注释测试类,这会导致此错误:

java.lang.IllegalStateException: Failed to load ApplicationContext

在错误堆栈跟踪的更下方,我看到抛出了以下异常:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource': Invocation of init method failed; nested exception is java.lang.IllegalStateException: Failed to replace DataSource with an embedded database for tests. If you want an embedded database please put a supported one on the classpath or tune the replace attribute of @AutoconfigureTestDatabase.

这是我正在处理的测试类:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
@DataJpaTest
public class AuthenticationControllerFTest {
@Autowired 
private MockMvc mockMvc;
@MockBean
private AuthenticationManager authenticationManager;
@Autowired
private WebApplicationContext context;
@Autowired
private Filter springSecurityFilterChain;
@Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(context)
.addFilters(springSecurityFilterChain).build();
}
@Test
public void testCreate() throws Exception {
String exampleUserInfo = "{"name":"Salam12333","username":"test@test1.com","password":"Salam12345"}";
RequestBuilder requestBuilder = MockMvcRequestBuilders
.post("/signup")
.accept(MediaType.APPLICATION_JSON).content(exampleUserInfo)
.contentType(MediaType.APPLICATION_JSON);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
MockHttpServletResponse response = result.getResponse();
int status = response.getStatus();
Assert.assertEquals("http response status is wrong", 200, status);
}
}

是什么导致了此错误?

编辑1这是我application.properties的内容:

spring.datasource.username = hello
spring.datasource.password = hello
spring.datasource.driver-class-name= com.mysql.jdbc.Driver
spring.datasource.url = jdbc:mysql://localhost:3306/myproject?useSSL=false
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE
logging.level.org.springframework.web=DEBUG
server.port = 8443
server.ssl.key-store = classpath:tomcat.keystore
server.ssl.key-store-password = hello
server.ssl.key-password = hello
server.ssl.enabled = true
server.ssl.key-alias=myproject

编辑 2

我在pom.xml中添加了以下内容:

<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>test</scope>
</dependency>

我创建了包含以下内容的application-test.properties

spring.datasource.username= root
spring.datasource.password= password
spring.datasource.driver-class-name= org.h2.Driver
spring.datasource.url= jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
  1. 什么是用户名和密码?我应该在哪里设置它们?
  2. 我还向测试类添加了@ActiveProfiles("test"),当我运行测试时,我收到一个错误,其中包括以下行:

Caused by: org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set

假设你用@SpringBootApplication注释类,这启用了自动配置,并且你H2依赖于类路径(见下文(,Spring Boot会看到内存数据库依赖H2,它将创建javax.sql.DataSource实现。默认连接 URLjdbc:h2:mem:testdb,默认用户名和密码为:用户名:sa 和密码:空。

应用程序属性文件

spring.datasource.url=jdbc:h2:mem:tesdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.testWhileIdle = true
spring.datasource.validationQuery = SELECT 1
spring.jpa.show-sql = true
spring.h2.console.enabled=true // if you need console

H2 依赖关系

<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency> // If you need h2 web console 
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

您可以访问 h2 控制台进行管理http://localhost:8080/h2-console

要使用内存数据库测试 REST 服务,您需要执行以下操作:
1. 在 pom 中添加 h2 依赖.xml

<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>

2. 在 application.properties 或 application.yaml 中定义 h2 配置

spring.jpa.database = h2
spring.datasource.url=jdbc:hsqldb:mem:testdb
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.HSQLDialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create

3. 注释您的测试类

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

完整的代码将如下所示:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class AuthenticationControllerFTest {
@Autowired 
private MockMvc mockMvc;
@MockBean
private AuthenticationManager authenticationManager;
@Autowired
private WebApplicationContext context;
@Autowired
private Filter springSecurityFilterChain;
@Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(context)
.addFilters(springSecurityFilterChain).build();
}
@Test
public void testCreate() throws Exception {
String exampleUserInfo = "{"name":"Salam12333","username":"test@test1.com","password":"Salam12345"}";
RequestBuilder requestBuilder = MockMvcRequestBuilders
.post("/signup")
.accept(MediaType.APPLICATION_JSON).content(exampleUserInfo)
.contentType(MediaType.APPLICATION_JSON);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
MockHttpServletResponse response = result.getResponse();
int status = response.getStatus();
Assert.assertEquals("http response status is wrong", 200, status);
}
}

删除注释@AutoConfigureMockMvc和@DataJpaTest。您正在尝试测试完整的应用程序,因此需要@SpringBootTest注释。 仅当您只想测试数据应用程序切片时,才需要@DataJpaTest。看看这个: https://spring.io/blog/2016/04/15/testing-improvements-in-spring-boot-1-4

在 Spring 引导中,我们不需要为内存数据库配置添加任何其他内容,除了类路径上的 jar 文件和类路径上的应用程序属性文件 (application.properties((如果使用 mavensrc/test/resources(,其余的事情将由 Spring 引导(引导之美(处理。

另一种选择是在类路径src/amin/resources(例如application-test.properties(上提供特定于配置文件的属性文件

这两个文件都对测试配置有效

属性文件的示例配置如下(考虑类路径上的 HSQL DB jar(:

spring.jpa.hibernate.ddl-auto = create-drop
spring.jpa.database = HSQL
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.HSQLDialect
spring.datasource.driverClassName = org.hsqldb.jdbcDriver
spring.datasource.url: jdbc:hsqldb:mem:scratchdb
spring.datasource.username = sa
spring.datasource.password = pass

也许这会有所帮助。

spring.datasource.url=jdbc:hsqldb:mem:testdb
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.HSQLDialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create

另请参阅在 Spring 中配置特定的内存数据库以进行测试

我相信,您可以在下面的内存数据库中使用集成测试-

如果您使用的是 json[b](虽然它在 DB2 中,但某些操作(如插入/更新(不支持我们的代码(数据类型或 DB2 中不存在的任何其他字段(兼容性问题(,这也将有所帮助。

然后参考这个测试容器 - 堆栈溢出答案

庞.xml

<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<version>1.15.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.15.1</version>
<scope>test</scope>
</dependency>

XyzIT.java

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
@Testcontainers
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
@Test
void test(){
var mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/opportunities/process")
.header("emailId", "ravi.parekh@xyz.com")
.header("Authorization", "authorization")
.header("Content-Type", "application/json").content(objectMapper.writeValueAsString(opportunity))).andReturn();
}

应用程序测试.yml

datasource:
initialization-mode: always
schema: classpath*:schema-h2.sql  #initial sql script to createDB
url: jdbc:tc:postgresql:11.9:///
jpa:
hibernate.ddl-auto: none
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
format_sql: true
default_schema: public
show-sql: true

最新更新