【问题标题】:Can't mock repository when testing with mockmvc使用 mockmvc 进行测试时无法模拟存储库
【发布时间】:2019-12-16 08:44:35
【问题描述】:

我有一个非常简单的控制器类和一个简单的 (jpa) 存储库。 我想要做的是测试它的 api 但模拟它的存储库并让它返回一个对象或不取决于测试用例。

我现在的问题是我不知道该怎么做。

我知道如何模拟存储库并使用 @Mock / @InjectMocks / when().return() 将其注入控制器/服务类

但是当我想在使用 MockMvc 发出请求后做同样的事情时,我失败了。 任何帮助都非常感谢

控制器


import java.util.Optional;

@RestController
@Slf4j
public class ReceiptController implements ReceiptsApi {

    @Autowired
    private ReceiptRepository receiptRepository;
    @Autowired
    private ErrorResponseExceptionFactory exceptionFactory;
    @Autowired
    private ApiErrorResponseFactory errorResponseFactory;

    @Override
    public Receipt getReceipt(Long id) {
        Optional<ReceiptEntity> result = receiptRepository.findById(id);
        if (result.isEmpty()) {
            throw invalid("id");
        }
        ReceiptEntity receipt = result.get();
        return Receipt.builder().id(receipt.getId()).purchaseId(receipt.getPurchaseId()).payload(receipt.getHtml()).build();
    }

    private ErrorResponseException invalid(String paramName) {
        return exceptionFactory.errorResponse(
                errorResponseFactory.create(HttpStatus.NOT_FOUND.value(), "NOT_VALID", String.format("receipt with id %s not found.", paramName))
        );
    }
}

这是测试类

@WebMvcTest(ReceiptController.class)
@RestClientTest
public class ReceiptControllerTest {

    @InjectMocks
    private ReceiptController receiptController;
    @Mock
    private ReceiptRepository receiptRepository;
    @Mock
    private ErrorResponseExceptionFactory exceptionFactory;
    @Mock
    private ApiErrorResponseFactory errorResponseFactory;

    private MockMvc mvc;


    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        mvc = MockMvcBuilders.standaloneSetup(
                new ReceiptController())
                      .build();
    }

    @Test
    public void getReceiptNotFoundByRequest() throws Exception {
        mvc.perform(MockMvcRequestBuilders
                            .get("/receipt/1")
                            .header("host", "localhost:1348")
                            .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isNotFound());
    }

    //TODO: Finish this test
    @Test
    public void getReceiptFoundByRequest() throws Exception {
        ReceiptEntity receipt1 = ReceiptEntity.builder().id(99999L).purchaseId(432L).html("<html>").build();
        when(receiptRepository.findById(1L)).thenReturn(Optional.of(ReceiptEntity.builder().id(1L).purchaseId(42L).html("<html></html>").build()));

        ResultActions result = mvc.perform(get("/receipt/1")
                                                   .header("host", "localhost:1348")
                                                   .accept(MediaType.APPLICATION_JSON))
                                       .andExpect(status().isOk());
    }

【问题讨论】:

    标签: java spring-boot testing


    【解决方案1】:

    在您的 setUp() 方法中,您使用 Mockito 模拟带有 @Mock 注释的 bean,并将它们注入到 ReceiptController 的新实例中,然后将其放入带有 @InjectMocks 注释的字段中。

    在下一行,您将使用 ReceiptController 的新实例(您使用 new ReceiptController())设置 MockMvc,而不是使用 Mockito 创建的实例。这意味着该实例中的所有字段都是null

    这几乎可以归结为Why is my Spring @Autowired field null


    要解决这个问题,您可以将receiptController 传递给 MockMvc。在这种情况下,您还可以删除 @WebMvcTest@RestClientTest,因为您不使用它们。

    或者,您可以使用@RunWith(SpringRunner.class) 设置测试,并使用@Autowired 代替@InjectMocks@MockBean 代替@Mock 正确设置Spring 测试。在这种情况下,您根本不需要 setUp() 方法,因为 MockMvc 可以由 Spring 自动装配。

    【讨论】:

      【解决方案2】:

      @WebMvcTest 和 MockMvc 允许您进行集成测试,而不是单元测试。

      它们允许您启动实际的 Spring 应用程序(使用随机端口)并测试实际的控制器类及其依赖项。这意味着您在测试顶部声明的变量实际上并未在当前设置中使用。

      如果您希望对控制器进行单元测试,您可以删除 @WebMvcTest,创建模拟依赖项(就像您所做的那样)并直接调用您的方法,而不是使用 MockMvc。

      如果您真的希望编写集成测试,则需要模拟您的外部依赖项(例如数据库)。您可以在测试环境中配置spring使用嵌入式数据库(例如H2),这样就不会影响您的真实数据库。

      在此处查看示例:https://www.baeldung.com/spring-testing-separate-data-source

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-09
        • 1970-01-01
        • 2019-08-31
        • 2016-12-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多