Spring mvc 无法使用带spring web mvc的mockito从模拟控制器调用模拟服务中的方法
我正在尝试为spring mvc rest控制器和由控制器访问的服务创建JUnit测试用例。Spring mvc 无法使用带spring web mvc的mockito从模拟控制器调用模拟服务中的方法,spring-mvc,mockito,junit4,Spring Mvc,Mockito,Junit4,我正在尝试为spring mvc rest控制器和由控制器访问的服务创建JUnit测试用例。 我使用Mockito来做上述工作。我能够从测试用例中成功地调用模拟注入控制器,并且当我调试时,我看到模拟的userService在模拟控制器中可用,但是服务对象中的方法没有被调用。在调试时,我观察到它只是跳过服务方法调用。 我也没有看到任何例外 RequestBuilder builder = MockMvcRequestBuilders.post("/service/user/register/")
我使用Mockito来做上述工作。我能够从测试用例中成功地调用模拟注入控制器,并且当我调试时,我看到模拟的userService在模拟控制器中可用,但是服务对象中的方法没有被调用。在调试时,我观察到它只是跳过服务方法调用。
我也没有看到任何例外
RequestBuilder builder = MockMvcRequestBuilders.post("/service/user/register/")
.contentType(MediaType.APPLICATION_JSON).content(convertObjectToJsonBytes(user));
mockMvc.perform(builder).andExpect(MockMvcResultMatchers.status().isOk());
Mockito.verify(userService, Mockito.times(1)).registerUser(Mockito.any(User.class));
我正在使用
RequestBuilder builder = MockMvcRequestBuilders.post("/service/user/register/")
.contentType(MediaType.APPLICATION_JSON).content(convertObjectToJsonBytes(user));
mockMvc.perform(builder).andExpect(MockMvcResultMatchers.status().isOk());
Mockito.verify(userService, Mockito.times(1)).registerUser(Mockito.any(User.class));
RequestBuilder builder = MockMvcRequestBuilders.post("/service/user/register/")
.contentType(MediaType.APPLICATION_JSON).content(convertObjectToJsonBytes(user));
mockMvc.perform(builder).andExpect(MockMvcResultMatchers.status().isOk());
Mockito.verify(userService, Mockito.times(1)).registerUser(Mockito.any(User.class));
1。测试类
package controller;
import java.io.IOException;
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.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.myPackage.model.User;
import com.myPackage.service.IUserService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/spring/application-config.xml")
public class UserControllerTest {
private MockMvc mockMvc;
@Mock
private IUserService userService;
@InjectMocks
private UserController controller;
@Before
public void setup(){
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
@Test
public void testRegisterUser()throws Exception{
User user = new User();
user.setCity("City");
user.setTown("Town");
user.setFirstname("Name");
user.setLastname("LastName");
user.setPassword("abc@123");
user.setUsername("abc@gmail.com");
RequestBuilder builder = MockMvcRequestBuilders.post("/service/user/register/")
.contentType(MediaType.APPLICATION_JSON).content(convertObjectToJsonBytes(user));
mockMvc.perform(builder).andExpect(MockMvcResultMatchers.status().isOk());
}
public static byte[] convertObjectToJsonBytes(Object object) throws IOException {
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsBytes(object);
}
}
RequestBuilder builder = MockMvcRequestBuilders.post("/service/user/register/")
.contentType(MediaType.APPLICATION_JSON).content(convertObjectToJsonBytes(user));
mockMvc.perform(builder).andExpect(MockMvcResultMatchers.status().isOk());
Mockito.verify(userService, Mockito.times(1)).registerUser(Mockito.any(User.class));
2。正在测试的控制器
package com.myPackage.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.myPackage.model.User;
import com.myPackage.service.IUserService;
@RestController
@RequestMapping("/service/user")
public class UserController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
@Autowired
private IUserService userService;
public IUserService getUserService() {
return userService;
}
public void setUserService(IUserService userService) {
this.userService = userService;
}
@RequestMapping(value = "/register/", method = RequestMethod.POST,headers="Accept=application/json")
public String registerUser(@RequestBody User user) {
logger.info("register user:"+user.toString());
String userDetails = userService.registerUser(user);
logger.info("user registered:"+userDetails);
return userDetails;
}
}
RequestBuilder builder = MockMvcRequestBuilders.post("/service/user/register/")
.contentType(MediaType.APPLICATION_JSON).content(convertObjectToJsonBytes(user));
mockMvc.perform(builder).andExpect(MockMvcResultMatchers.status().isOk());
Mockito.verify(userService, Mockito.times(1)).registerUser(Mockito.any(User.class));
3。测试中控制器内要调用的服务
package com.myPackage.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.myPackage.model.User;
import com.myPackage.service.IUserService;
@RestController
@RequestMapping("/service/user")
public class UserController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
@Autowired
private IUserService userService;
public IUserService getUserService() {
return userService;
}
public void setUserService(IUserService userService) {
this.userService = userService;
}
@RequestMapping(value = "/register/", method = RequestMethod.POST,headers="Accept=application/json")
public String registerUser(@RequestBody User user) {
logger.info("register user:"+user.toString());
String userDetails = userService.registerUser(user);
logger.info("user registered:"+userDetails);
return userDetails;
}
}
RequestBuilder builder = MockMvcRequestBuilders.post("/service/user/register/")
.contentType(MediaType.APPLICATION_JSON).content(convertObjectToJsonBytes(user));
mockMvc.perform(builder).andExpect(MockMvcResultMatchers.status().isOk());
Mockito.verify(userService, Mockito.times(1)).registerUser(Mockito.any(User.class));
服务方法registerUser将从上面的控制器调用。当我们运行测试用例时,我没有看到任何日志打印在控制台上。此外,在调试时,我看到创建了以下类型的UserService实例-IUserService$$EnhancerByMockitoWithCGLIB$$c00081eb,但当我深入挖掘所有以查看mockhandlers注册方法下的方法列表时,我只在调用列表中看到“toString”方法。不确定这是否给出了一些指示,说明了为什么在测试用例期间没有调用下面服务类中的方法“registerUser”
package com.myPackage.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;
import com.myPackage.dao.IUserDao;
import com.myPackage.model.User;
import com.myPackage.model.UserInfo;
@Service("userService")
public class UserService implements IUserService {
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
@Autowired
private IUserDao userDao;
public IUserDao getUserDao() {
return userDao;
}
public void setUserDao(IUserDao userDao) {
this.userDao = userDao;
}
@Override
public String registerUser(User user) {
// TODO Auto-generated method stub
logger.info("New User for registration:",user);
if(user!=null && user.getUsername()!=null){
User alreadyExist = userDao.getUserByLogin(user.getUsername());
if(alreadyExist!=null){
return "userAlreadyExists";
}
}
logger.info("New User for registration complete:",user.getUser_id());
return null;
}
}
RequestBuilder builder = MockMvcRequestBuilders.post("/service/user/register/")
.contentType(MediaType.APPLICATION_JSON).content(convertObjectToJsonBytes(user));
mockMvc.perform(builder).andExpect(MockMvcResultMatchers.status().isOk());
Mockito.verify(userService, Mockito.times(1)).registerUser(Mockito.any(User.class));
4。由上面第3点中的UserService类实现的接口
RequestBuilder builder = MockMvcRequestBuilders.post("/service/user/register/")
.contentType(MediaType.APPLICATION_JSON).content(convertObjectToJsonBytes(user));
mockMvc.perform(builder).andExpect(MockMvcResultMatchers.status().isOk());
Mockito.verify(userService, Mockito.times(1)).registerUser(Mockito.any(User.class));
IUserService。上面测试类中的模拟userService是IUserService类型
package com.myPackage.service;
import com.myPackage.model.User;
import com.myPackage.model.UserInfo;
public interface IUserService {
public String registerUser(User user);
}
RequestBuilder builder = MockMvcRequestBuilders.post("/service/user/register/")
.contentType(MediaType.APPLICATION_JSON).content(convertObjectToJsonBytes(user));
mockMvc.perform(builder).andExpect(MockMvcResultMatchers.status().isOk());
Mockito.verify(userService, Mockito.times(1)).registerUser(Mockito.any(User.class));
userService中的方法(读取代码)永远不会从控制器中实际调用,因为它已被mockito模拟
RequestBuilder builder = MockMvcRequestBuilders.post("/service/user/register/")
.contentType(MediaType.APPLICATION_JSON).content(convertObjectToJsonBytes(user));
mockMvc.perform(builder).andExpect(MockMvcResultMatchers.status().isOk());
Mockito.verify(userService, Mockito.times(1)).registerUser(Mockito.any(User.class));
您已通过以下操作定义了这一点:
@Mock
private IUserService userService;
@InjectMocks
private UserController controller;
MockitoAnnotations.initMocks(this);
RequestBuilder builder = MockMvcRequestBuilders.post("/service/user/register/")
.contentType(MediaType.APPLICATION_JSON).content(convertObjectToJsonBytes(user));
mockMvc.perform(builder).andExpect(MockMvcResultMatchers.status().isOk());
Mockito.verify(userService, Mockito.times(1)).registerUser(Mockito.any(User.class));
如果要断言已调用该方法,可以使用
verify(userService, times(1)).registerUser(any(User.class));
RequestBuilder builder = MockMvcRequestBuilders.post("/service/user/register/")
.contentType(MediaType.APPLICATION_JSON).content(convertObjectToJsonBytes(user));
mockMvc.perform(builder).andExpect(MockMvcResultMatchers.status().isOk());
Mockito.verify(userService, Mockito.times(1)).registerUser(Mockito.any(User.class));
@乔纳斯:谢谢你的洞察力。如果我不模拟userService,那么在单元测试时,userService在与registerUser匹配的userController方法下被发现为null。所以在读了某个地方之后,我嘲笑了userService。同样,在按照您的建议进行更改之后,仍然不会调用模拟服务方法-下面是我的更改-
RequestBuilder builder = MockMvcRequestBuilders.post("/service/user/register/")
.contentType(MediaType.APPLICATION_JSON).content(convertObjectToJsonBytes(user));
mockMvc.perform(builder).andExpect(MockMvcResultMatchers.status().isOk());
Mockito.verify(userService, Mockito.times(1)).registerUser(Mockito.any(User.class));
如果要测试实际的服务方法,请自动连线:
RequestBuilder builder = MockMvcRequestBuilders.post("/service/user/register/")
.contentType(MediaType.APPLICATION_JSON).content(convertObjectToJsonBytes(user));
mockMvc.perform(builder).andExpect(MockMvcResultMatchers.status().isOk());
Mockito.verify(userService, Mockito.times(1)).registerUser(Mockito.any(User.class));
@Autowired
private IUserService userService;
如果要像现在这样使用模拟,则需要存根该方法:
RequestBuilder builder = MockMvcRequestBuilders.post("/service/user/register/")
.contentType(MediaType.APPLICATION_JSON).content(convertObjectToJsonBytes(user));
mockMvc.perform(builder).andExpect(MockMvcResultMatchers.status().isOk());
Mockito.verify(userService, Mockito.times(1)).registerUser(Mockito.any(User.class));
when(userService.registerUser(any(User.class))).thenReturn("expected string");
:谢谢你的洞察力。如果我不模拟userService,那么在单元测试时,userService在与registerUser匹配的userController方法下被发现为null。所以在读了某个地方之后,我嘲笑了userService。同样在按照您的建议进行更改之后,模拟服务方法仍然没有被调用-下面是我的更改-mockMvc.perform(builder.andExpect(MockMvcResultMatchers.status().isOk());验证(userService,Mockito.times(1)).registerUser(Mockito.any(User.class));userService为null,因为它可能在spring上下文中不可用。在测试中添加“com.myPackage.service”的@Component扫描。对于另一个问题,在处理模拟对象时,它永远不会被实际调用。再次感谢您的宝贵意见。使用@ComponentScan(“com.myPackage.service”)也没有帮助,测试中的控制器中的服务实例仍然为空。但我理解的是,如果我尝试模拟,那么我将能够调用该服务,因为它只是下面Khalid提到的存根。令人失望的是,我接受了这样一个事实,即我无法在服务中调用该方法,同时让控制器处于测试状态。我希望有一个出路,因为我想在一个测试用例中检查完整的流。感谢Khalid的输入@Autowired并没有使服务类实例化,但stubing方法让我明白我不能调用该方法,我所能做的就是复制该行为。虽然我希望有一种方法可以在单个测试用例中测试从控制器到服务再到dao的完整流程。您可以使用。如果您检查上面的测试类,我已经在遵循Spring集成测试文档中提到的内容。我们在测试开始时加载应用程序上下文,在测试类顶部使用以下代码,也使用SpringJUnit4ClassRunner-@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations=“classpath:/spring/application config.xml”)@WebAppConfiguration公共类UserControllerTest{}