Spring 使用@WebMvcTest 启动单元测试 - 执行不会从控制器进入服务层并且 returns null 没有错误

Spring boot Unit test with @WebMvcTest - execution doesn't enter service layer from controller and returns null without error

我正在为我的 spring 引导应用程序的控制器编写单元测试。 我有典型的 MVC classes:ObjectSchemaController、ObjectSchemaService 和 ObjectSchemaDao。 我用@WebMvcTest 编写了单元测试,并用@MockBean 模拟了我的服务和 dao class。 (遵循本指南:https://www.baeldung.com/spring-boot-testing

下面是我的单元测试:

@RunWith(SpringRunner.class)
@WebMvcTest(ObjectSchemaController.class)
public class ObjectSchemaControllerTest2 {
    @Autowired
    private MockMvc mvc;
    @MockBean
    private ObjectSchemaService service;
    @MockBean
    private ObjectSchemaDao dao;
    @Autowired
    ObjectMapper objectMapper;
    @Test
    public void testCreateObjectSchemaPass() throws Exception {
        String payload = "{\"some_key\":\"some val\"}";
        ObjectSchema objectSchema = objectMapper.readValue(payload, ObjectSchema.class);

        Mockito.when(service.createSchema(objectSchema))
        .thenReturn(objectSchema);
        Mockito.when(dao.createSchema(objectSchema)).thenReturn(objectSchema);

        mvc.perform(MockMvcRequestBuilders.post("/objectservice/schema/")
       .contentType("application/json")
       .content(objectMapper.writeValueAsString(objectSchema)))
       .andExpect(status().isOk());
    }

}

下面是我的服务class:

@Service
public class ObjectSchemaService {
    @Autowired
    ObjectSchemaDao objectSchemaDao;

    public ObjectSchema createSchema(@Valid ObjectSchema objectSchema)throws Exception {
        return objectSchemaDao.createSchema(objectSchema);
    }
}

我在单元测试中遇到的问题是,服务层没有执行并且 returns 空值。

当我调试时,我可以看到执行到达我的控制器 class 并且 ObjectSchemaService 在控制器中被 mockito-mocked。但是执行永远不会进入服务层,服务方法返回的值为空。

我参考了其他指南 - 他们正在执行类似的步骤。但它不适合我。我在这里错过了什么?

我也看到这个 post 有类似的问题。

我确保我的实际控制器和我在单元案例中传递的输入对象都是相同的实例 class。

您正在嘲笑 ObjectSchemaService 但没有预期的行为。 您需要为被模拟的服务设置行为。因此,根据方法签名和结果的一些想法。

Mockito.when(service.createSchema(Mockito.any(ObjectSchema.class)).thenReturn(objectSchema);

目前 ObjectSchemaService 模拟只是 returns 一个 default value,在你的情况下它是 null。

In order to be transparent and unobtrusive all Mockito mocks by default return 'nice' values. For example: zeros, falseys, empty collections or nulls.

如果您使用 ObjectSchemaService 的详细信息更新您的答案,我也可以更新我的答案。

您模拟了 ObjectSchemaService,因此您需要告诉服务如何在调用方法时模拟来自服务的值。如果你不模拟服务的值,Mockito 不知道他们必须 return 总是给你 null。不需要在此测试中模拟 ObjectSchemaDao。

注意:我在代码中使用了Lombok作为ObjectSchema.builder()到return对象存储到数据库时的Id,可以使用构造函数。假设服务return对象.

代码如下所示:

import static org.mockito.BDDMockito.given;

@Test
public void testCreateObjectSchemaPass() throws Exception {
        String payload = "{\"some_key\":\"some val\"}";
        ObjectSchema objectSchema = objectMapper.readValue(payload, ObjectSchema.class);
        given(service.createSchema(objectSchema)).willReturn(
                ObjectSchema.builder()
                        .id(1)
                        .someKey("Some Val")
                        .build());
        mvc.perform(MockMvcRequestBuilders.post("/objectservice/schema/").contentType("application/json").content(objectMapper.writeValueAsString(objectSchema)))
                .andExpect(status().isOk());
    }