上一篇博客已经完成了spring4.3与junit4.12的整合,如有疑问欢迎一起探讨学习。接下来将展示单元测试及mockmvc使用。
1、Controller层,在这也是我需要测试的层
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping(value="/")
public class DmController {
@Autowired
private DmService dmService; //服务接口
//保存对象
@RequestMapping(value="newdm.do",method = RequestMethod.POST)
@ResponseBody
public Object newdm(HttpSession session, DmDTO dmDTO) {
User user = getUser(session);
String name = user.getName();
if(name != null) {
String result = dmService.save(dmDTO);
return Message(String); //Message用于向前端返回数据对象
}
return null;
}
//get请求,用作页面跳转
@RequestMapping(value="returnjsp.do",method=RequestMethod.GET)
public String turnjsp(String id) {
if(id.equals("one")) {
return "/hello/one";
}else {
return "/hello/other";
}
}
}
DmService接口
public interface DmService {
String save(DmDTO dmDTO);
}
DmServiceImpl实现类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service //要记得加上这个注解,否则无法注入容器
public class DmServiceImpl implements DmService{
@Autowired
private DmDAO dmDAO;
@Override
public String save(DmDTO dmDTO) {
if(dmDTO != null) {
String result = dmDAO.save(dmDTO);
return result;
}
return null;
}
}
DmDAO接口
public interface DmDAO {
String save(DmDTO dmDTO);
}
DmDAOImpl实现类
@Repository //切记要加上该注解
public class DmDAOImpl implements DmDAO{
//真实的DAO实现类中应该是与数据库交互,这里为了方便就不写了
@Override
public String save(DmDTO dmDTO) {
@Override
public String save(DmDTO dmDTO) {
if(dmDTO.getName().length()<5) {
return "保存成功";
}else {
return "保存失败";
}
}
}
单元测试案例:
package cn.wolfcode;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.request.MockMvcResultHandlers.status;
import static org.springframework.test.web.servlet.request.MockMvcResultHandlers.view;
//测试类,需要继承前面整合好的BaseJunit
public class DmControllerTest extends BaseJunit{
@Autowired
DmController dmController; //这里是直接从容器中拿出DmController这个bean,这个bean里使用到的依赖,比如DmService都
@Test //已经注入到这个bean里,所以下面可以直接用这个bean来调用newdm方法进行测试
public void testNewdm() { //注意:测试方法不能有返回值,也不能是有参函数
DmDTO dmDTO = new DmDTO();
dmDTO.setName("hao"); //设置长度小于5,应该返回保存成功
Message result =(Message) dmController.newdm(session,dmDTO); //这里使用到的session在BaseJunit中已经使用mockmvc构造了
assertEquals("保存成功",result.getinfo()); //返回的对象获取里面的信息
}
//使用mockmc来测试,mockmvc主要是模拟页面对后台的访问,个人用的不是很习惯
@Test
public void testNewdmWithMockmvc() {
DmDTO dmDTO = new DmDTO();
dmDTO.setName("hao");
String requestJson = JSONObject.toJSONString(dmDTO);//mockmvc只能传string类型,对于这种对象类型的需要转成String类型
mockMvc.perform(post("newdm.do") //这里的mockMvc在BaseJunit已经定义好,请求url及请求方式,如果被测方法是get,这里对应的换成get即可
.contentType(MediaType.APPLICATION_JSON) //接受的数据类型
.content(requestJson) //请求的数据内容
.andExpect(status().isOk()) //断言返回的状态是正确的
.session(session) //session的方式,括号内的session也是BaseJunit里构造好的,可以根据自己的要求构造
).andDo(print()) //结果处理器,用于在控台上打印结果 注意这里是需要静态引入
.andReturn();
}
@Test
public void testTurnjsp() {
mockMvc.perform(get("returnjsp.do")) //使用get请求
.andExpect(status().isOk())
.andExpect(view().name("/hello/one")) //使用断言判断返回结果
.andDO(print())
.andReturn();
}
}
这里也把之前的BaseJunit放出来吧
import javax.sql.DataSource;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.mock.jndi.SimpleNamingContextBuilder;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.ModelMap;
import org.springframework.web.context.WebApplicationContext;
@RunWith(SpringJUnit4ClassRunner.class) //指定运行的测试类 该类在spring-test里,有时无法引入只能手工敲了
@ContextConfiguration(locations= {"classpath*:/applicationContext.xml"})//spring-test里的类,这个很重要,把配置文件里的内容加载到容器中
@WebAppConfiguration
@Transactional(transactionManager="transactionMananger") //这里的事务即是取applicationContext.xml的事务
@Rollback //默认为true 即事务回滚
public class BaseJunit {
@Autowired
protected WebApplicationContext wac;
protected MockMvc mockMvc;
protected MockHttpSession session;
protected MockHttpServletRequest request;
protected ModelMap map;
@BeforeClass //Junit里的方法,在整个单元测试运行之前先运行,所以可以用于加载xml等文件操作,这里加载jndi.xml,
public static void beforeClass() throws Exception{ //这样就解决了JNDI连接方式不启动tomcat无法连接数据库的问题
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("classpath*:/jndi.xml");//加一个*会整个项目去找这个xml
DataSource ds = (DataSource) app.getBean("dataSource"); //我们jndi.xml里配置的数据源id="dataSource"
SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
builder.bind("java:com/env/jdbc/hello",ds);//数据源与applicationContext.xml里的jndiName的value绑定
builder.activate();
}
@Before //每个测试用例执行前都会执行一次
public void setup() { //这里使用MockMvc构造各种session等,这个看个人需要吧
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
this.session = new MockHttpSession();
this.request = new MockHttpServletRequest();
this.map = new ModelMap();
User us = new User(); //用户实体类
us.setUmname("lixiaolong");
session.setAttribute("user",us);
}
}
总结:
由于我们使用的是存储过程,存储过程里有commit,所以单元测试执行存储过程后是无法事务回滚的,这个问题我们后面会使用强大的Jmockit来完成。时间问题,后面再来补充经常遇到的报错问题,重点是后面的Jmockit强大的功能使用。
常见问题:1、org.springframework.beans.factory.NoSuchBeanDefinitionException:No bean named ‘dataSource’ is defind…
主要是没有加载到数据源,可以查看数据库配置是否有问题以及加载的jndi.xm路径是否正确了
2、java.lang.IllegalStateException:Failed to load ApplicationContext…
Caused by:org.springframework.beans.factory.UnsatisfiedDependencyException:Error creating bean with name ‘*’:Unsatisfied dependency expressed field ‘’; …
没加@Service/@Repository/@Controller这些注解的话就会报创建bean错误的异常。
3、java.lang.IllegalStateException:Failed to load ApplicationContext…
Caused by:java.lang.IllegalStateException:WebApplicationObjectSupport instance[ResourceHttpRequestHandler[locations=[class path resource[easyui/]],resolvers=…]]…
在测试类上加上@WebAppConfiguration注解即可,如BaseJunit里就加了该注解。