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

时间:2017-07-27 05:46:35

标签: java spring testing spring-boot

我正在为Spring boot Rest控制器编写测试。此休止控制器将一些值写入db。

我想使用Spring为此测试提供的内存数据库。根据{{​​3}},我必须使用@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. 什么是用户名和passowrd?我应该在哪里设置它们?
  2. 我还在测试类中添加了@ActiveProfiles("test"),当我运行测试时出现错误,其中包含以下行:
  3. Caused by: org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set

6 个答案:

答案 0 :(得分:7)

假设您使用@SpringBootApplication注释类,它启用了自动配置,并且您对类路径具有H2依赖性(请参阅下文)Spring Boot将看到H2内存数据库依赖,它将创建javax.sql.DataSource实现。默认连接URL为jdbc:h2:mem:testdb,默认用户名和密码为:username:sa和password:empty。

application.properties文件

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

答案 1 :(得分:3)

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

<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);
    }
}

答案 2 :(得分:2)

在spring boot中,除了类路径上的jar文件和类路径上的应用程序属性文件(application.properties)之外,我们不需要在内存数据库配置中添加任何额外的东西(src/test/resources如果maven使用)其余的东​​西将由春季靴子(靴子之美)照顾。

另一个选择是在类路径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

答案 3 :(得分:1)

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

答案 4 :(得分:1)

也许这有帮助。

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

另见Configure specific in memory database for testing purpose in Spring

答案 5 :(得分:1)

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

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

然后参考这个TestContainer - Stackoverflow answer

Pom.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();

}

应用程序-test.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