Spring Boot 如何设置MockMvc,使测试不会相互影响

bvhaajcl  于 2023-04-20  发布在  Spring
关注(0)|答案(2)|浏览(148)

我正在设置一个integrationtest来检查spring应用程序是否在控制器级别工作,旁边是我的单元测试。我确实知道我正在测试的工作,单元测试工作,我已经用postman做了所有的事情。每个integrationtest也单独工作,并给出我期望它给出的结果。问题是当我一起运行它们时,有些测试不再工作了。这是因为MockMvc应该在每次测试时都被更新,但事实并非如此。
我尝试通过手动设置mockMvc来获得这种行为,而不是将其注入到构造函数中,但同样的行为仍然存在。我想我设置MockMvc是错误的,但我似乎无法弄清楚如何正确设置它。我使用Sping Boot 3和Java 20。
我应该如何创建mock,以便它在每个测试中再次运行,并且不会受到其他测试的影响?我将testclass放在下面。

@SpringBootTest
@AutoConfigureMockMvc
public class EmployeeControllorIntegrationTest {

    private final static String URI = "/employees/";
    private ObjectMapper objectMapper;

    private MockMvc mockMvc;

    public EmployeeControllorIntegrationTest(MockMvc mockMvc, ObjectMapper objectMapper) {
        this.mockMvc = mockMvc;
        this.objectMapper = objectMapper;
    }

    @Test
    void getAllEmployeesThrowsExceptionWhenEmpty() throws Exception{
        String error = mockMvc.perform(get(URI+"showAll"))
                .andExpect(status().isAccepted())
                .andExpect(content().contentType("application/json"))
                .andReturn().getResolvedException().getMessage();

        assertThat(error).isEqualTo("No employees present");
    }
    @Test
    void getAllEmployeesWorksWhenEmployeesPresent() throws Exception{
        this.insertUnitAndLevel();
        EmployeeDto employeeDto = new EmployeeDto("employeeName", "employeeNameSurname", LocalDate.of(2000,04,23),1L,1L);

        mockMvc.perform(post(URI+"addEmployee")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(employeeDto)));

        MockHttpServletResponse response = mockMvc.perform(get(URI+"showAll"))
                .andExpect(status().isOk())
                .andExpect(content().contentType("application/json"))
                .andReturn().getResponse();

        Employee[] allLevels = objectMapper.readValue(response.getContentAsString(), Employee[].class);

        assertThat(allLevels).hasSize(1);
        assertThat(Arrays.stream(allLevels).findFirst().get().getName()).isEqualTo("employeeName");
        assertThat(Arrays.stream(allLevels).findAny().get().getName()).isEqualTo("employeeName");
        assertThat(Arrays.stream(allLevels).findFirst().get().getStartDateContract()).isEqualTo(LocalDate.now());
        assertThat(Arrays.stream(allLevels).findAny().get().getStartDateContract()).isEqualTo(LocalDate.now());
    }

    @Test
    void addNewEmployeeWithInvalidNameThrowsError() throws Exception{
        this.insertUnitAndLevel();
        EmployeeDto employeeDto = new EmployeeDto(" ", "employeeNameSurname", LocalDate.of(2000,04,23),1L,1L);
        String error = mockMvc.perform(post(URI+"addEmployee")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(employeeDto)))
                .andExpect(status().isBadRequest())
                .andExpect(content().contentType("application/json"))
                .andReturn().getResolvedException().getMessage();

        assertThat(error).isEqualTo("Cannot be empty or blank");
    }
    @Test
    void addNewEmployeeWithInvalidSurnameThrowsError() throws Exception{
        this.insertUnitAndLevel();
        EmployeeDto employeeDto = new EmployeeDto("employeeName", " ", LocalDate.of(2000,04,23),1L,1L);
        String error = mockMvc.perform(post(URI+"addEmployee")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(employeeDto)))
                .andExpect(status().isBadRequest())
                .andExpect(content().contentType("application/json"))
                .andReturn().getResolvedException().getMessage();

        assertThat(error).isEqualTo("Cannot be empty or blank");
    }



    @Test
    void addingNewEmployeeWithAlreadyExistingNameSurnameAndBirthdateThrowsError() throws Exception{
        this.insertUnitAndLevel();
        EmployeeDto employeeDto = new EmployeeDto("employeeName", "employeeSurname", LocalDate.of(2000,04,23),1L,1L);
        EmployeeDto employeeDtoCopy = new EmployeeDto("employeeName", "employeeSurname", LocalDate.of(2000,04,23),1L,1L);

        mockMvc.perform(post(URI+"addEmployee")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(employeeDto)));

        String error = mockMvc.perform(post(URI+"addEmployee")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(employeeDtoCopy)))
                .andExpect(status().isConflict())
                .andExpect(content().contentType("application/json"))
                .andReturn().getResolvedException().getMessage();

        assertThat(error).isEqualTo("employee with that name, surname and date of birth already exists");
    }


    @Test
    void addingValidEmployeeWorks() throws Exception{
        this.insertUnitAndLevel();
        EmployeeDto employeeDto = new EmployeeDto("employeeName", "employeeSurname", LocalDate.of(2000,04,23),1L,1L);

        mockMvc.perform(post(URI+"addEmployee")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(employeeDto)))
                .andExpect(status().isOk())
                .andExpect(content().contentType("text/plain;charset=UTF-8"))
                .andExpect(content().string("New employee added succesfully"));

    }

    private void insertUnitAndLevel() throws Exception{
        EnumerationLevel mocklevel = new EnumerationLevel("A1", "Mockdescripition");

        mockMvc.perform(post("/units/addUnit")
                .contentType(MediaType.APPLICATION_JSON)
                .content("new unit"));

        mockMvc.perform(post("/levels/addLevel")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(mocklevel)));
    }

}
u3r8eeie

u3r8eeie1#

使用MockMvcBuilders你可以创建mockMvc对象。你需要自动连接WebApplicationContext

@Autowired
private WebApplicationContext context;

@BeforeEach
void setupTests() {
    mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
}

如果还想应用安全性,则使用

@Autowired
private WebApplicationContext context;

@BeforeEach
void setupTests() {
    mockMvc = MockMvcBuilders.webAppContextSetup(context).apply(springSecurity()).build();
}

这将分别为每个测试用例生成MockMvc对象。

wswtfjt7

wswtfjt72#

手动清除db很有帮助。在每次测试之前示例化mock是不必要的,只需将其注入构造函数并清除db即可。尽管spring docs声明如Dhaval所说的那样示例化mock,但这并没有在使用后清空mock。我将其注入构造函数并使用@AutoConfigureMockMvc annotation。然后在每次测试之前清除db,它就可以工作了。

@BeforeEach
    void clearDatabase(@Autowired JdbcTemplate jdbcTemplate) {
        JdbcTestUtils.deleteFromTables(jdbcTemplate, "employees");
        JdbcTestUtils.deleteFromTables(jdbcTemplate, "enumerationlevels");
        JdbcTestUtils.deleteFromTables(jdbcTemplate, "units");
    }

将jdbcTemplate设置为变量并将其注入到构造函数中也可以工作

相关问题