如何在不加载 data.sql 的情况下 运行 REST 控制器测试?

How can I run a REST Controller test without loading data.sql?

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

INSERT INTO users(username,password, email) VALUES ('admin','a$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','a$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 脚本在每次测试时都在执行(我认为不应该是这种情况,因为我的控制器测试不应该依赖于数据库数据)。最重要的是,在执行每个 class 后数据没有被刷新,所以第一个工作正常,其余的抛出 @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) 但它并没有解决问题。

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

首先,您的问题是,您的整个 SpringBootApplication 已启动,因为您正在使用 @SpringBootTest,请改用 @WebMvcTest。您还“需要”使用

@LocalServerPort 
private int port;

实际访问您使用 (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

添加的端口

你的第二个问题

On top of that, the data is not being flushed after executing each class, so the first one works fine and the rest throw a @Unique exception because the data is already there.

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

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

@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 会按预期工作。