Spring @Mock注释的意义是什么?

Spring @Mock注释的意义是什么?,spring,spring-mvc,mockito,spring-test-mvc,springmockito,Spring,Spring Mvc,Mockito,Spring Test Mvc,Springmockito,我有一个关于在控制器测试中创建bean的问题。例如,有一个这样的测试 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {MainApplicationConfiguration.class, JPAConfig.class}) @WebAppConfiguration public class TestMainController { private MockMvc mockMvc;

我有一个关于在控制器测试中创建bean的问题。例如,有一个这样的测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {MainApplicationConfiguration.class, JPAConfig.class})
@WebAppConfiguration
public class TestMainController {

    private MockMvc mockMvc;
    @Before
    public void setUp() {
    MockitoAnnotations.initMocks(this);
    mockMvc = MockMvcBuilders.standaloneSetup(mainController).build();
    }
    @InjectMocks
    private MainController mainController;

    @Mock
    private EntryService entryService;

    @Autowired
    DBEntryRepository repository;

    @Test
    public void testEntryGet() throws Exception {

        List<DBEntry> response_data = new ArrayList<>();
        response_data.add(new DBEntry(1, 1, "STR", "DATE"));

        Mockito.when(entryService.findAllEntries())
                .thenReturn(response_data);
        MvcResult result = mockMvc.perform(get("/VT/entry/"))
                .andExpect(status().isOk()).andReturn();
        verify(entryService, times(1)).findAllEntries();
        verifyNoMoreInteractions(entryService);
    }
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(类={MainApplicationConfiguration.class,JPAConfig.class})
@WebAppConfiguration
公共类TestMainController{
私有MockMvc-MockMvc;
@以前
公共作废设置(){
initMocks(this);
mockMvc=MockMvcBuilders.standaloneSetup(mainController.build();
}
@注射模拟
专用主控制器;
@嘲弄
私人入口服务入口服务;
@自动连线
DBEntryRepository;
@试验
public void testEntryGet()引发异常{
列表响应_data=new ArrayList();
响应数据添加(新的数据库条目(1,1,“STR”,“DATE”);
Mockito.when(entryService.findAllEntries())
.然后返回(响应数据);
MvcResult result=mockMvc.perform(get(“/VT/entry/”)
.andExpect(status().isOk()).andReturn();
验证(entryService,次(1)).findAllEntries();
验证NomoreInteractions(entryService);
}
}
以及映射到上的控制器方法

/VT/入口/

@RequestMapping(value=“/entry/”,method=RequestMethod.POST)
public ResponseEntity createEntry(@RequestBody DBEntry entry,UriComponentsBuilder ucBuilder){
System.out.println(“创建条目”+entry.getNum());
试一试{
entryService.saveEntry(entry);
entryService.refreshEntryService();
}捕获(例外e){
e、 printStackTrace();
返回新的响应属性(HttpStatus.BAD_请求);
}
HttpHeaders=新的HttpHeaders();
headers.setLocation(ucBuilder.path(“/entry/{id}”).buildAndExpand(entry.getId()).toUri());
返回新的ResponseEntity(标题,HttpStatus.CREATED);
}
EntryService
使用
@Service
注释和
main应用程序配置进行注释。class
是使用
@EnableWebMvc
和此
EntryService
的扫描项目的配置

通过这一点,我想说明这个控制器在实际应用程序中确实使用了这个
EntryService
,并且所有这些都通过
MainApplicationConfiguration.class
进行了耦合

问题是:为什么带有
@Mock
注释的
entryService
最终出现在我测试执行范围内的控制器代码中?难道不应该只针对那个实例,并且控制器内部应该实例化另一个bean(EntryService),为什么这个注释模拟了该bean的所有出现(在测试范围内)?我在想,我应该编写整个其他上下文web上下文,而不是
main applicationconfiguration.class
,在内部模拟它并替换当前定义。我完全搞不懂为什么这个简单的注释会做出这样的事情

如果有人能理解这个魔法,请说出@InjectMock和@Mock的区别是什么

谢谢你的关注!如果我的问题很愚蠢的话,我很抱歉。我很新,它可以工作,但我还没有魔法。

在for
@InjectMocks
中:

Mockito将尝试按顺序仅通过构造函数注入、setter注入或属性注入来注入mock

因此,由于
EntryService
是控制器的依赖项,
@InjectMocks
将尝试在测试类中找到
EntryService
的模拟对象,并将其注入
mainController

请注意,只会发生构造函数注入、setter注入或属性注入中的一种

@Mock将字段标记为Mock对象。
@InjectMock将模拟对象注入到标记的字段中,但标记的字段不是模拟。

这不是问题主要部分的答案。@Alex我的评论中包含了差异。你可以从中看到更多。你知道,你试图引用一些东西,但这篇引用并不能回答这个问题(:谢谢你的努力!我的EntryService用@Mock annotation注释。@Alex不是你的问题“为什么
EntryService
@Mock
注释在我的测试执行范围内出现在我的控制器代码中?”?它位于控制器中,因为
main控制器上的
@InjectMocks
注释。
@RequestMapping(value = "/entry/", method = RequestMethod.POST)
    public ResponseEntity<Void> createEntry(@RequestBody DBEntry entry, UriComponentsBuilder ucBuilder) {
        System.out.println("Creating entry " + entry.getNum());
        try {
            entryService.saveEntry(entry);
            entryService.refreshEntryService();
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseEntity<Void>(HttpStatus.BAD_REQUEST);
        }
        HttpHeaders headers = new HttpHeaders();
        headers.setLocation(ucBuilder.path("/entry/{id}").buildAndExpand(entry.getId()).toUri());
        return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
    }