使用Mockito在REST控制器内部模拟类

时间:2015-06-22 13:16:20

标签: java testing junit spring-boot mockito

我有一个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)
    ...

可以请某人给我一个提示,这个模拟怎么可以注入我的控制器?

5 个答案:

答案 0 :(得分:4)

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

...

@Autowired
private Controller controller;

...

@Before
public void setUp() throws Exception {

    ...

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

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

重新设计控制器以使用构造函数注入而不是字段注入。这使得依赖项显式化并使您的测试设置更加简单。

答案 3 :(得分:0)

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

在上面,将您返回的值设为“您的返回值”,并在测试中使用此值来验证您的输出。

答案 4 :(得分:0)

您可以删除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将被模拟,模拟将被注入控制器。