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

Java 使用内存数据库为Rest控制器编写测试,java,spring,testing,spring-boot,Java,Spring,Testing,Spring Boot,我正在为Spring boot Rest控制器编写一个测试。此rest控制器将一些值写入数据库 我想使用Spring为这个测试提供的内存数据库。根据,我必须用@DataJpaTest注释测试类,这会导致此错误: java.lang.IllegalStateException: Failed to load ApplicationContext 在错误堆栈跟踪的更深处,我看到引发了以下异常: 原因:org.springframework.beans.factory.unsatifiedpende

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

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

java.lang.IllegalStateException: Failed to load ApplicationContext
在错误堆栈跟踪的更深处,我看到引发了以下异常:


原因:org.springframework.beans.factory.unsatifiedpendencyException:创建名为“org.springframework.boot.autoconfigure.orm.jpa.hibernatejpaaautoconfiguration”的bean时出错:通过构造函数参数0表示的未满足的依赖关系;嵌套异常为org.springframework.beans.factory.BeanCreationException:创建名为“dataSource”的bean时出错:调用init方法失败;嵌套异常为java.lang.IllegalStateException:无法使用嵌入式数据库替换数据源以进行测试。如果您想要一个嵌入式数据库,请将一个受支持的数据库放在类路径上,或者调整@AutoconfigureTestDatabase的replace属性。

这是我正在研究的测试类:

@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 这是我的
应用程序的内容。属性

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>
  • 用户名和密码是什么?我应该把它们放在哪里
  • 我还向测试类添加了
    @ActiveProfiles(“test”)
    ,当我运行测试时,我得到一个错误,其中包括以下行:

  • 原因:org.hibernate.hibernateeexception:当未设置“hibernate.dial”时,对方言解析信息的访问不能为null

    删除注释@AutoConfigureMockMvc和@DataJpaTest。您正在尝试测试完整的应用程序,因此需要@SpringBootTest注释@只有当您只想测试数据应用程序片时,才需要DataJpaTest。看看这个:

    也许这有帮助

    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
    

    另请参见

    假设您使用
    @SpringBootApplication
    注释类,这将启用自动配置,并且您对类路径有
    H2
    依赖关系(参见下文)
    springboot
    将在内存中看到
    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>
    
    
    com.h2数据库
    氢
    运行时
    //如果您需要h2 web控制台
    org.springframework.boot
    SpringBootStarterWeb
    

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

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

    另一个选项是在类路径
    src/amin/resources
    上提供特定于概要文件的属性文件(例如
    application test.properties

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

    下面给出了属性文件的示例配置(考虑类路径上的HSQL DB jar):


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

    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    
    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);
        }
    }
    

    我相信,你可以用下面的内存db进行集成测试-

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

    那么请参考这个

    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>
    
    Application-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
    

    但是我不想使用实际的数据库。我想使用内存中的数据库。当我删除这两个注释时,我会得到以下错误:
    通过字段“mockMvc”表示的未满足的依赖关系;嵌套的异常是org.springframework.beans.factory.NoSuchBeanDefinitionException:没有可用的“org.springframework.test.web.servlet.mockMvc”类型的合格bean:至少需要1个符合autowire候选资格的bean。依赖项批注:{@org.springframework.beans.factory.annotation.Autowired(required=true)}
    “如果需要嵌入式数据库,请将受支持的数据库放在类路径上,或调整@AutoconfigureTestDatabase的replace属性”。那么,您是否在类路径上放置了嵌入式数据库?我将我的
    应用程序.properties
    文件内容添加到原始的post.application.properties中。属性不会影响类路径。您需要将h2或hsqldb添加到pom.xml中。我添加了它,请参见编辑2。
    spring.datasource.url=jdbc:h2:mem:db;db\u CLOSE\u DELAY=-1
    --h2不是hsqldb。请看下面的答案。慢慢来,小心一点。我假设我必须首先配置hsqldb,对吗?有没有办法在Java中设置
    用户名
    密码
    并创建
    testdb
    ?数据库在内存中…创建
    testdb
    是什么意思?Hibernate将在启动时从您的实体创建表。如果您想用值预加载它,您必须使用SQL脚本。如果您有其他问题,请搜索SQL脚本或提出新问题。我的问题是关于您的答案。
    username
    password
    的值来自何处?据我所知,它试图使用提供的值连接到
    testdb
    属性
    username
    password
    。它们是为hsqldb硬编码的。我认为任何数据库名称都可以,请参阅。
    username
    password
    的值是默认值吗?如果不是,我应该在哪里设置它们?
    @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);
        }
    }
    
        <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>
    
    @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();
    
    }
    
      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