【问题标题】:Mockito Spring Data Web SupportMockito Spring Data Web 支持
【发布时间】:2023-03-10 23:15:01
【问题描述】:

我是 Mockito 的新手,在 Spring Data Web 支持方面有点问题。

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

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

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

问题是,当我在我的 unitTests 中使用 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());
    }
}

非常感谢任何帮助。

【问题讨论】:

  • 你使用 Spring Boot 吗?
  • 你能添加一个你的单元测试的例子吗?
  • @alayor 当然,我这样做了。
  • @MaciejWalkowiak 是的,我愿意。

标签: spring spring-mvc spring-data mockito mockmvc


【解决方案1】:

要返回给定 id 的 MyObject,您可以使用 when(…​.).thenReturn(…​.)。因此,当您在 SomeService 中有一个方法可以通过 id 查找 MyObject 时,您可以对它进行存根并返回值。

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

【讨论】:

  • 抱歉,您没有收到。
  • 用 MyObject 替换 id 是由 Spring DI 在调用 Controllermethod 之前完成的,它不使用 SomeService 而是使用 org.springframework.data.repository.CrudRepository 的实现,在现实世界的场景中它会在类路径,但我的 MockMvc 由于某种原因没有使用它。
【解决方案2】:

我认为如果你只使用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())
    }
}

【讨论】:

  • 这行得通,但它没有测试,我想要它测试什么。测试的目的是验证对 /?id=1 的请求最终是否会调用 controller.delete() 在您的情况下,这不再是测试的一部分。
【解决方案3】:

这个解决方案非常简单,只花了我 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();

它奏效了。

【讨论】:

    【解决方案4】:

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

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

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

    你可以看看this资源。

    【讨论】:

      【解决方案5】:

      如何让 Spring 使用 mockRepository 将 /?id=1 中传递的 id 替换为我选择的 MyObject 实例

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-03-01
        • 2014-07-06
        • 1970-01-01
        • 1970-01-01
        • 2016-03-25
        • 1970-01-01
        • 2023-03-24
        • 2018-06-20
        相关资源
        最近更新 更多