我正在尝试为控制器访问的spring mvc rest控制器和服务创建一个JUnit测试用例。
我正在使用Mockito来做上述事情。我能够从测试用例中成功调用模拟注入控制器,并且当我调试时,我看到模拟的控制器中可以使用模拟的userService,但是不会调用服务对象中的方法。在调试时我发现它只是跨越了服务方法调用。
我也没有看到任何例外。
我正在使用
我已粘贴下面的代码:
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);
}
}
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;
}
}
第3。要在测试中的控制器中调用的服务
服务方法registerUser将从上面的控制器调用。在运行测试用例时,我没有看到任何日志在控制台上打印。另外在调试时我看到类似这样的userSerivice实例--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;
}
}
4。 UserService类在上面第3点实现的接口
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);
}
答案 0 :(得分:1)
您的userService中的方法(读取代码)实际上永远不会从您的控制器中调用,因为它已经被mockito模仿了。
您已经通过以下方式自行定义:
@Mock
private IUserService userService;
@InjectMocks
private UserController controller;
MockitoAnnotations.initMocks(this);
如果你想声明方法已被调用,你可以使用,
verify(userService, times(1)).registerUser(any(User.class));
答案 1 :(得分:0)
@Jonas:感谢您的见解。如果我没有模拟userService,那么在单元测试时,userService在userUtroller方法匹配registerUser下找到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));
答案 2 :(得分:0)
如果您想测试实际的服务方法,请自动加载它:
@Autowired
private IUserService userService;
如果你想使用你现在正在做的模拟,你需要存根方法:
when(userService.registerUser(any(User.class))).thenReturn("expected string");