Mockito Spring 数据网络支持

Mockito Spring Data Web Support

我是 Mockito 的新手,在 Spring 数据 Web 支持方面有一些问题。

我的控制器中有以下功能。

@DeleteMapping("/")
public MyObject delete(@RequestParam("id")MyObject object){
...do something
}

描述了这里发生的事情(在实际用例中)here

问题是,当我在单元测试中使用 MockMvc 和 Mockito 时,没有数据库,也没有持久性存储库。我怎样才能让 Spring 使用 mockRepository 将 /?id=1 中移交的 ID 替换为我选择的 MyObject 实例。

这是测试的样子:

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import com.mine.OrgUnitController;
import com.mine.OrgUnitService;

@RunWith(SpringJUnit4ClassRunner.class)
public class OrgUnitControllerTest2 {
    private MockMvc mockMvc;
    @Mock
    SomeService someService;
    @InjectMocks
    MyController controller;

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
        mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
    }

    @Test
    public void test_delete() throws Exception {
        mockMvc.perform(delete("/?id=1")).andExpect(status().isOk());
    }
}

非常感谢任何帮助。

要return一个给定id的MyObject,你可以使用when(…​.).thenReturn(…​.)。因此,当您在 SomeService 中有一个通过 id 查找 MyObject 的方法时,您可以存根这个和 return 值。

// When the get method is called, it will return MyObject
when(someService.get(id)).thenReturn(new MyObject());

我想如果你只使用 Mockito 而不是 Mockito + MockMvc.

对你来说会更容易

你可以这样做:

@RunWith(SpringJUnit4ClassRunner.class)
public class OrgUnitControllerTest2 {
    @Mock
    SomeService someService;
    @InjectMocks
    MyController controller;

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void test_delete() throws Exception {
        //given
        given(someService.delete(1)).willReturn(true); //or successful response

        //when
        MyObject response = controller.delete(1);

        //then
        assertTrue(OK, response.getStatus())
    }
}

好吧,解决方案非常简单,只花了我 2 天的时间。 ;) 为了使 SpringDataWebSupport 工作 spring 使用 org.springframework.data.repository.support.DomainClassConverter 这是一个 ConversionService。接下来要知道的是 MockMvc 通过 setConversionService() 接受 ConversionService。所以剩下要做的唯一一件事就是编写我自己的 ConversionService,这实际上非常简单。我这样扩展 DefaultFormattingConversionService

public class MockSpringDataWebSupport extends DefaultFormattingConversionService {
    /**
     * @param converters {@link Converter Converters} that shall be added to this {@link ConversionService}
     */
    @SafeVarargs
    public MockSpringDataWebSupport(Converter<? extends Object, ? extends Object>... converters) {
        for (Converter<? extends Object, ? extends Object> converter : converters) {
            this.addConverter(converter);
        }
    }
}

这样我就可以交出任何符合我测试需要的自定义转换器。在这种特殊情况下,我使用了:

        mockMvc = MockMvcBuilders.standaloneSetup(controller)
            .setConversionService(new MockSpringDataWebSupport(new Converter<String, MyObject>() {
                @Override
                public OrgUnit convert(String source) {
                    return new MyObject();
                }
            })).build();

它奏效了。

您可能需要在 MockMvc 对象中设置 setCustomArgumentResolvers,如下所示:

@Before
  public void init() {
      MockitoAnnotations.initMocks(this);
      mockMvc = MockMvcBuilders
          .standaloneSetup(controller)
          .setCustomArgumentResolvers(new HandlerMethodArgumentResolver(){...})
          .build();
   }

您需要弄清楚哪个 class 正在实现 HandlerMethodArgumentResolver,然后在上面的 init() 方法中使用它。

您可以查看 this 资源。

How can i make Spring use a mockRepository to replace the id handed over in /?id=1 by a MyObject-instance of my choice

您可以通过模拟 WebConversionService 来做到这一点,这将避免通过实体存储库 findById 进行数据库查找。您还可以设置要使用的实例,而无需从数据库中获取实例。有关如何模拟此服务的更多详细信息,请查看 .