【问题标题】:How can I run a REST Controller test without loading data.sql?如何在不加载 data.sql 的情况下运行 REST 控制器测试?
【发布时间】:2022-01-17 10:40:34
【问题描述】:

我正在开发一个 Spring Boot 应用程序,但在设置 RESTController 测试时遇到了一些问题。问题是,当我单独运行测试类时,它们都可以工作。但是,当我尝试一次运行所有测试类时,只有第一个有效,其他的则抛出 java.lang.IllegalStateException: Failed to load ApplicationContext。我一直在调试这个,有问题的行如下:

INSERT INTO users(username,password, email) VALUES ('admin','$2a$10$bicbzJTFskk8.sHWJauxCu2RzDIqXk/zCxQDZ5ByLQw0m0lQ6l2Pa', 'admin@mail.com') [23505-200] Caused by: org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #1 of URL [file:spring-boot/target/classes/db/hsqldb/data.sql]: INSERT INTO users(username,password, email) VALUES ('admin','$2a$10$bicbzJTFskk8.sHWJauxCu2RzDIqXk/zCxQDZ5ByLQw0m0lQ6l2Pa', 'admin@mail.com'); nested exception is org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Unique index or primary key violation: "PUBLIC.PRIMARY_KEY_4D ON PUBLIC.USERS(USERNAME) VALUES 1"; SQL statement:

这让我认为data.sql 脚本正在每个测试中执行(我认为不应该是这种情况,因为我的控制器测试不应该依赖数据库数据)。最重要的是,在执行每个类后数据不会被刷新,所以第一个工作正常,其余的抛出 @Unique 异常,因为数据已经存在。

我的 REST 控制器测试如下所示:

@DirtiesContext(classMode = ClassMode.BEFORE_CLASS)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc(addFilters = false)
public class GameControllerTest {

    @Autowired
    MockMvc mockMvc;

    @MockBean
    GameService gameService;

    @BeforeEach
    void setup() {
        Game game1 = new Game();
        game1.setId(1);

        Game game2 = new Game();
        game2.setId(2);

        Lobby lobby = new Lobby();

        when(gameService.findAll()).thenReturn(List.of(game1, game2));
        when(gameService.createFromLobby(lobby)).thenReturn(game1);
        when(gameService.gameCount()).thenReturn(List.of(game1, game2).size());
        when(gameService.findGameById(1)).thenReturn(game1);

    }

    @Test
    void testGetAllGames() throws Exception {
        mockMvc.perform(get("/games")).andExpect(status().isOk()).andExpect(jsonPath("$", hasSize(2)))
                .andExpect(jsonPath("$[0].id", is(1)))
                .andExpect(jsonPath("$[1].id", is(2)));
    }

如您所见,我也尝试使用@DirtiesContext(classMode = ClassMode.BEFORE_CLASS),但并不能解决问题。

【问题讨论】:

  • 你正在编写一个完整的集成测试,这就是@SpringBootTest。您想要的是为您的特定控制器使用@WebMvcTest

标签: java spring spring-boot spring-restcontroller spring-boot-test


【解决方案1】:

我觉得这个问题有两个不同的问题。

首先您的问题是,您的整个 SpringBootApplication 已启动,因为您使用的是 @SpringBootTest,而是使用 @WebMvcTest。你也“需要”使用

@LocalServerPort 
private int port;

实际访问您使用(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 添加的端口

你的第二个问题

最重要的是,在执行每个类后数据不会被刷新,所以第一个工作正常,其余的抛出一个 @Unique 异常,因为数据已经存在。

可以通过使用 @Transactional 注释您的测试来轻松修复,但我认为这不是您实际问题的解决方案。

【讨论】:

    【解决方案2】:

    感谢两位的回答。我必须进行以下更改:

    @ExtendWith(SpringExtension.class)
    @WebMvcTest(controllers = GameController.class)
    public class GameControllerTest {
    
        @Autowired
        MockMvc mockMvc;
    
        @MockBean
        private GameService gameService;
    
        // I also have to mock all the services called from gameService:
    
        @MockBean
        private UserService userService;
    
        @MockBean
        private PlayerService playerService;
    
        @MockBean
        private DataSource dataSource; 
    
        // (...)
    

    我不知道我还必须模拟那些未被服务直接调用的服务。这样,@WebMvcTest 按预期工作。

    【讨论】:

      猜你喜欢
      • 2011-07-25
      • 1970-01-01
      • 2023-03-18
      • 1970-01-01
      • 2011-06-13
      • 1970-01-01
      • 2019-09-23
      • 2018-05-28
      • 1970-01-01
      相关资源
      最近更新 更多