Spring Web 单元测试实用HelloWorld(附代码)
2015-11-27 19:45
591 查看
什么是Mokito?它有什么用?
在简单的java 项目中,如果要做单元测试比较方便,利用Junit工具甚至直接写一个main()方法就可以实现。但是到了web项目中,要做单元测试就没那么简单了。笔者往常的开发测试过程往往是这样的,写好一堆的前端后台方法(没有前端,只好自己一起做了),目测过一遍代码逻辑觉得没问题之后就扔到jetty插件中去跑一遍。出现异常后,通过断点调试找到并解决问题,重启一次jetty,重复以上过程。很明显,这样的做法效率是很低的。最近抽了点时间,学习了一下如果在Java web中进行单元测试。下面首先介绍下如何在项目中简单应用这个技术,随后会尽可能介绍下相关原理。
How?
目标代码展示
项目结构图:
pom.xml
<properties> <main.basedir>${project.basedir}</main.basedir> <spring.version>4.2.3.RELEASE</spring.version> <mybatis.version>3.3.0</mybatis.version> <mybatis-spring.version>1.2.3</mybatis-spring.version> <mybatis-generator.version>1.3.2</mybatis-generator.version> <javax.servlet-api>3.1.0</javax.servlet-api> <commons-dbcp.version>1.4</commons-dbcp.version> <mysql-connector-java.version>5.1.35</mysql-connector-java.version> <jstl.version>1.2</jstl.version> <jetty.port>8080</jetty.port> <jackson.codehaus.version>1.9.13</jackson.codehaus.version> <jackson.fasterxml.version>2.6.3</jackson.fasterxml.version> <testng.version>6.8.1</testng.version> <jsonpath.version>0.8.1</jsonpath.version> <jetty.version>8.1.16.v20140903</jetty.version> </properties> <dependencies> <!-- SPRING --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <!-- SPRING --> <!-- mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>${mybatis.version}</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>${mybatis-spring.version}</version> </dependency> <!-- mybatis --> <!-- mybatis generator --> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>${mybatis-generator.version}</version> </dependency> <!-- mybatis generator --> <!-- javax --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${javax.servlet-api}</version> </dependency> <!-- javax --> <!-- dbcp database connection pool --> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>${commons-dbcp.version}</version> </dependency> <!-- dbcp database connection pool --> <!-- jdbc driver --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql-connector-java.version}</version> </dependency> <!-- jdbc driver --> <!-- jstl --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>${jstl.version}</version> </dependency> <!-- jstl --> <!-- Jackson --> <!-- Notice: codehaus is old version of fasterxml --> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-core-asl</artifactId> <version>${jackson.codehaus.version}</version> </dependency> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> <version>${jackson.codehaus.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>${jackson.fasterxml.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.fasterxml.version}</version> </dependency> <!-- Jackson --> <!-- Testing Dependencies --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>${testng.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>com.jayway.jsonpath</groupId> <artifactId>json-path</artifactId> <version>${jsonpath.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!-- Testing Dependencies --> </dependencies>
MyBatisController.java
/** * MyBatisController.java */ import com.del.entity.Blog; import com.del.service.MyBatisService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView; import java.util.HashMap; import java.util.Map; @Controller @RequestMapping("mybatis") public class MyBatisController { @Autowired private MyBatisService myBatisService; @RequestMapping("getAllBlog") public ModelAndView getAllBlog(){ ModelAndView modelAndView = new ModelAndView("mybatis"); modelAndView.addObject("result", myBatisService.getBlog(new Blog())); return modelAndView; } @RequestMapping("getBlogById") public ModelAndView getBlogById(@RequestParam Integer id){ ModelAndView modelAndView = new ModelAndView("mybatis"); Blog blog = new Blog(); blog.setId(id); modelAndView.addObject("result", myBatisService.getBlog(blog)); return modelAndView; } @RequestMapping("getBlogByClass") public ModelAndView getBlogByClass(@RequestBody Blog blog){ ModelAndView modelAndView = new ModelAndView("mybatis"); modelAndView.addObject("result", myBatisService.getBlog(blog)); return modelAndView; } @ResponseBody @RequestMapping(value = "deleteBlogById", method = RequestMethod.POST) public Map<String,Object> deleteBlogById(@RequestParam Integer id){ Map<String,Object> resultMap = new HashMap<String, Object>(); boolean isSucceed = myBatisService.delete(id); if (isSucceed){ resultMap.put("status",Boolean.TRUE); resultMap.put("message","Success!"); } else { resultMap.put("status",Boolean.FALSE); resultMap.put("message","Error!"); } return resultMap; } }
MyBatisService.java
/** * MyBatisService.java,提供了对数据库中数据进行增删改的操作。细节不做介绍,有疑问请参照别的资料。 */ import com.del.dao.IBlogDao; import com.del.entity.Blog; import com.del.entity.BlogExample; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class MyBatisService { @Autowired private IBlogDao iBlogDao; public List<Blog> getBlog(Blog blog){ BlogExample blogExample = new BlogExample(); BlogExample.Criteria criteria = blogExample.createCriteria(); if (blog.getId() != null){ criteria.andIdEqualTo(blog.getId()); } if (blog.getName() != null){ criteria.andNameEqualTo(blog.getName()); } if (blog.getSize() != null){ criteria.andSizeEqualTo(blog.getSize()); } List<Blog> list = iBlogDao.selectByExample(blogExample); return list; } public boolean insert(Blog blog){ int count = iBlogDao.insert(blog); return count==1?true:false; } public boolean delete(Integer id){ int count = iBlogDao.deleteByPrimaryKey(id); return count==1?true:false; } }
可以看到目标代码很简单,就是监听几个url查找数据库,然后将查询结果通过modal传到jsp,jsp再做相应的展示工作. 大家应该可以很简单看懂.
下面我们就进入正戏,开始做单元测试.
单元测试
UnitTest.java
/** * UnitTest.java **/ import com.del.entity.Blog; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.testng.AbstractTestNGSpringContextTests; 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.web.context.WebApplicationContext; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.List; 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.result.MockMvcResultMatchers.*; @ContextConfiguration(locations = {"classpath*:platform-services-servlet.xml", "classpath*:mybatis-context.xml"}) @WebAppConfiguration public class UnitTest extends AbstractTestNGSpringContextTests { private MockMvc mockMvc; @Autowired private WebApplicationContext webApplicationContext; @BeforeClass public void setup(){ this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build(); } /** * 简单测试post请求结果 * @throws Exception */ @Test(priority = 1) public void testIndex() throws Exception { mockMvc.perform(get("/main/index")) .andExpect(status().isOk()) .andExpect(view().name("main")); System.out.println("testIndex..."); } /** * 测试简单的get请求方法 * @throws Exception */ @Test(priority = 2) public void testSelect() throws Exception { List<Blog> result = new ArrayList<Blog>(); Blog blog1 = new Blog(1,"first",1); Blog blog2 = new Blog(2,"second",2); Blog blog3 = new Blog(3,"three",3); result.add(blog1); result.add(blog2); result.add(blog3); mockMvc.perform(get("/mybatis/getAllBlog")) .andExpect(status().isOk()) .andExpect(view().name("mybatis")) /** * 这里要注意!!要想用例中可以利用andExpect()方法比较对象,目标类必须有合法的equals()方法! */ .andExpect(model().attribute("result",result)); System.out.println("testSelect..."); } /** * 测试附带请求参数的post请求方法 * @throws Exception */ @Test(priority = 3) public void testGetBlogById() throws Exception { Blog blog = new Blog(1,"first",1); List<Blog> result = new ArrayList<Blog>(); result.add(blog); mockMvc.perform(post("/mybatis/getBlogById").param("id", "1")) .andExpect(status().isOk()) .andExpect(model().attribute("result",result)); System.out.println("testGetBlogById..."); } /** * 测试附带复杂对象的post请求方法 * @throws Exception */ @Test(priority = 4) public void testGetBlogByClass() throws Exception { Blog blog = new Blog(); blog.setId(1); Blog expectBlog = new Blog(1,"first",1); List<Blog> expectResult = new ArrayList<Blog>(); expectResult.add(expectBlog); mockMvc.perform(post("/mybatis/getBlogByClass") .content(asJsonString(blog)) .contentType(MediaType.APPLICATION_JSON_UTF8)) .andExpect(status().isOk()) .andExpect(model().attribute("result",expectResult)); System.out.println("testGetBlogByClass..."); } /** * 测试接收经过jackson转化的json格式返回结果 * @throws Exception */ @Test(priority = 5) public void testDeleteBlogById() throws Exception { mockMvc.perform(post("/mybatis/deleteBlogById").param("id","3")) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)) .andExpect(jsonPath("$.message").value("Success!")); System.out.println("testDeleteBlogById..."); } public static String asJsonString(final Object obj) { try { final ObjectMapper mapper = new ObjectMapper(); final String jsonContent = mapper.writeValueAsString(obj); return jsonContent; } catch (Exception e) { throw new RuntimeException(e); } } }
Why?
略读测试代码
待完善…相关文章推荐
- Java 结构体排序
- 解决Spring AOP Controller 不生效
- java hdu2088
- hadoop2.5.2 eclipse 插件编译
- eclipse 打开.java文件乱码
- 如何实现java 日期加减
- JAVA字符串转日期或日期转字符串
- java继承在程序中的运用
- MyBatis中$和#的区别
- 使用 Spring、Elasticsearch 及 Logstash 构建企业级数据搜索和分析平台
- Java对象的强、软、弱和虚引用
- java面向对象基础知识(五)
- java栈与堆的区别
- Java内存泄露的理解与解决
- Java内存泄露原因详解
- 【玩转Eclipse】——eclipse实现代码块折叠-类似于VS中的#region……#endregion
- Java_解密ThreadLocal
- javaSE(10)(Map集合)
- Java加密技术(一)——BASE64与单向加密算法MD5&SHA&MAC
- 2.1 Spring容器的基本实现--Spring源码深度解析