How do I check the DB state in an integration test? Is injecting a JdbcTemplate the only option?
For example, you test a PATCH that, if successful, should update certain table cells.
I can't use a repository. This microservice can't select the entities it modifies. Adding select methods just for tests feels wrong.
import com.example.pixel_money_transfer_api.data.dto.request.TransferRequestDto;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.http.MediaType;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.web.servlet.MockMvc;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import java.math.BigDecimal;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@Testcontainers
@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class TransferControllerIntegrationTest {
@Container
@ServiceConnection
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16.0");
@Autowired
MockMvc mockMvc;
@Autowired
ObjectMapper objectMapper;
@Test
@Sql(statements = "TRUNCATE \"user\" CASCADE;")
@Sql(statements = """
INSERT INTO "user" (id, name) VALUES (15, 'Sasha');
INSERT INTO "user" (id, name) VALUES (16, 'Alex');
INSERT INTO account (id, user_id, balance) VALUES (1, 15, 10);
INSERT INTO account (id, user_id, balance) VALUES (2, 16, 0);
""")
void performTransfer_ifUserHasSufficientBalance_recipientHasAccount_returns200() throws Exception {
TransferRequestDto transferDto = new TransferRequestDto();
transferDto.setRecipientId(16L);
transferDto.setAmount(BigDecimal.valueOf(10L));
mockMvc.perform(patch("/api/money-transfer")
.with(jwt().jwt(jwt -> jwt
.claim("userid", 15L)))
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(transferDto)))
.andExpect(status().isOk());
// now I should somehow assert against the DB state
}
}
JdbcTemplateis fine. You can also read the DB using your own repository object (presumably the same object that wrote to the DB during the test). You could even read the DB using whatever business API you have for reads.select * from userwould do, and you may not need much custom code to achieve that.select * from user? An autowiredEntityManager?