使用 Mockito 在 REST 控制器中模拟类
Posted
技术标签:
【中文标题】使用 Mockito 在 REST 控制器中模拟类【英文标题】:Mock class inside REST controller with Mockito 【发布时间】:2015-09-07 23:08:34 【问题描述】:我有一个 spring-boot 应用程序,它通过控制器公开一个 REST 接口。这是我的控制器的一个例子:
@RestController
public class Controller
@Autowired
private Processor processor;
@RequestMapping("/magic")
public void handleRequest()
// process the POST request
processor.process();
我正在尝试为此类编写单元测试,并且必须模拟处理器(因为处理需要很长时间,并且在测试控制器行为期间我试图避免此步骤)。请注意,为了这个问题,提供的示例已简化。
我正在尝试使用 mockito 框架来完成这项任务:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = App.class)
@WebAppConfiguration
@ActiveProfiles("test")
public class ControllerTest
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
@Before
public void setUp() throws Exception
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
Processor processor = Mockito.mock(Processor.class);
ReflectionTestUtils.setField(Controller.class, "processor", processor);
@Test
public void testControllerEmptyBody() throws Exception
this.mockMvc.perform(post("/magic")).andExpect(status().isOk());
但是,这失败了
java.lang.IllegalArgumentException: Could not find field [processor] of type [null] on target [class org.company.Controller]
at org.springframework.test.util.ReflectionTestUtils.setField(ReflectionTestUtils.java:112)
...
请有人给我一个提示,如何将这个模拟注入到我的控制器中?
【问题讨论】:
【参考方案1】:你不应该传递一个实例来设置字段,而不是类,例如:
...
@Autowired
private Controller controller;
...
@Before
public void setUp() throws Exception
...
Processor processor = Mockito.mock(Processor.class);
ReflectionTestUtils.setField(controller, "processor", processor);
【讨论】:
有趣...我没有想到我也可以自动连接控制器。谢谢。像魅力一样工作!【参考方案2】:我认为你可以像这样直接注入模拟:
@InjectMocks
private ProcessorImpl processorMock;
并删除这一行:
ReflectionTestUtils.setField(Controller.class, "processor", processor);
见Injection of a mock object into an object to be tested declared as a field in the test does not work using Mockito?
【讨论】:
尝试使用 injectMocks 注释,但它不起作用(原始处理器被调用)。甚至尝试将其命名为与控制器内的字段名称相同...【参考方案3】:重新设计您的控制器以使用构造函数注入而不是字段注入。这使依赖关系变得明确,并使您的测试设置变得更加简单。
【讨论】:
【参考方案4】:@Before
public void setUp() throws Exception
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
Processor processor = Mockito.mock(Processor.class);
//This line should be added to perform mock for Processor.
Mockito.when(processor.process()).thenReturn(<Your returned value>);
//ReflectionTestUtils.setField(Controller.class, "processor", processor);
在上面将您的返回值放入“您的返回值”,并在测试中使用此值来验证您的输出。
【讨论】:
【参考方案5】:您可以删除SpringApplicationConfiguration
中的servlet 上下文类并模拟servlet 上下文。不需要注入WebApplicationContext
和ReflectionTestUtils
。
基本上,您的代码应如下所示:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MockServletContext.class)
@WebAppConfiguration
@ActiveProfiles("test")
public class ControllerTest
@InjectMocks
private MyController controller;
@Mock
private Processor processor;
private MockMvc mockMvc;
@Before
public void setUp() throws Exception
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
@Test
public void testControllerEmptyBody() throws Exception
when(proessor.process()).thenReturn(<yourValue>);
this.mockMvc.perform(post("/magic")).andExpect(status().isOk());
verify(processor, times(<number of times>)).process();
Processor
将被模拟,模拟将被注入控制器。
【讨论】:
以上是关于使用 Mockito 在 REST 控制器中模拟类的主要内容,如果未能解决你的问题,请参考以下文章
如何模拟 JWT 令牌以将其与 Mockito 和 Spring Boot 一起使用
如何使用 Mockito 对 void 方法的行为进行编程? [复制]