Spring Web 单元测试实用HelloWorld(附代码)

什么是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?

略读测试代码

待完善…

展开阅读全文

没有更多推荐了,返回首页