I'm developing a Spring Boot application and I'm having some trouble setting up RESTController tests. The problem is that, when I run the test classes individually, they all work. However, when I try to run all the test classes at once, only the first one works and the others throw java.lang.IllegalStateException: Failed to load ApplicationContext
. I have been debugging this and the problematic line is the following:
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:
This leads me to think that the data.sql
script is being executed on every test (which I believe should not be the case since my controller tests shouldn't rely on DB data). 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.
My REST controller tests look like this:
@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)));
}
As you can see, I also tried to use @DirtiesContext(classMode = ClassMode.BEFORE_CLASS)
but it does not fix the problem.
Thanks both for your answers. I had to do the following changes:
@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;
// (...)
I didn't know that I also had to mock the services that were not called directly by the service. This way, @WebMvcTest
works as expected.