用Mockito在REST控制器中模拟类

用Mockito在REST控制器中模拟类

问题描述:

我有一个通过控制器公开REST接口的spring-boot应用程序。这是我的控制器的例子:用Mockito在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) 
    ... 

能否请人给我一个提示,如何模拟可能在注入我的控制器?

你不是应该通过一个实例来设置字段,而不是类,例如:

... 

@Autowired 
private Controller controller; 

... 

@Before 
public void setUp() throws Exception { 

    ... 

    Processor processor = Mockito.mock(Processor.class); 
    ReflectionTestUtils.setField(controller, "processor", processor); 
} 
+0

有趣的...并没有出现在我身上,我也可以自动连接控制器。谢谢。奇迹般有效! – Smajl

我认为你可以直接注入像模拟:

@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?

+0

尝试使用injectMocks注释,但它不起作用(原始处理器被调用)。甚至试图将其命名为与控制器内部的字段名称相同... – Smajl

@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); 
    } 

在上面放置您的返回值为“您的返回值”并在测试中使用此值验证您的输出。

重做您的控制器以使用构造函数注入而不是字段注入。这使得依赖性显式化并使测试设置极其简单。

您可以删除SpringApplicationConfiguration和模拟servlet上下文中的servlet上下文类。不需要注入WebApplicationContextReflectionTestUtils

基本上,你的代码应该是这个样子:

@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会被嘲笑和模仿将被注入到控制器。