Spring整合MockMvc单元测试,Java配置

Spring整合MockMvc进行单元测试,首先添加Spring-Test maven依赖:

<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-testartifactId>
    <version>4.3.7.RELEASEversion>
dependency>

Java配置如下:

package com.bob.test.config;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.UnsupportedEncodingException;

import com.bob.config.mvc.model.User;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpSession;
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.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.WebApplicationContext;

import com.bob.config.mvc.MvcContextConfig;
import com.bob.config.mvc.exception.CustomizedException;
import com.bob.config.root.RootContextConfig;
import com.google.gson.Gson;

/**
 * @since 2016年12月8日 下午4:45:26
 * @author
 *
 */
@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class) 
//ContextConfiguration可以指定Java配置类,或者是配置文件,这里是基于Java配置形式
@ContextConfiguration(classes = { RootContextConfig.class, MvcContextConfig.class })
public abstract class BaseControllerTest {

    protected Gson gson;

    private MockMvc mockMvc;
    protected MockHttpSession session;

    protected Object mappedController;

    protected String userName;
    protected String password;

    protected boolean loginBefore;

    @Autowired
    protected WebApplicationContext webApplicationContext;

    @Before()
    public void setup() {
        gson = new Gson();
        // 初始化MockMvc对象
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); 
        init();
    }

    /**
     * @param urlTemplate
     * @param urlVariables
     * @return
     */
    public String getRequest(String urlTemplate, Object... urlVariables) {
        return doRequest(RequestMethod.GET, null, false, null, urlTemplate, urlVariables);
    }

    /**
     * @param urlTemplate
     * @param urlVariables
     * @return
     */
    public String getAsyncRequest(String urlTemplate, Object... urlVariables) {
        return doRequest(RequestMethod.GET, null, true, null, urlTemplate, urlVariables);
    }

    /**
     * @param contentType
     * @param content
     * @param urlTemplate
     * @param urlVariables
     * @return
     */
    public String postRequest(MediaType contentType, String content, String urlTemplate, Object... urlVariables) {
        return doRequest(RequestMethod.POST, contentType, false, content, urlTemplate, urlVariables);
    }

    /**
     * @param contentType
     * @param content
     * @param urlTemplate
     * @param urlVariables
     * @return
     */
    public String postAsyncRequest(MediaType contentType, String content, String urlTemplate, Object... urlVariables) {
        return doRequest(RequestMethod.POST, contentType, true, content, urlTemplate, urlVariables);
    }

    /**
     * @param content
     * @param urlTemplate
     * @param urlVariables
     * @return
     */
    public String postRequest(String content, String urlTemplate, Object... urlVariables) {
        return doRequest(RequestMethod.POST, MediaType.APPLICATION_JSON, false, content, urlTemplate, urlVariables);
    }

    /**
     * @param content
     * @param urlTemplate
     * @param urlVariables
     * @return
     */
    public String postAsyncRequest(String content, String urlTemplate, Object... urlVariables) {
        return doRequest(RequestMethod.POST, MediaType.APPLICATION_JSON, true, content, urlTemplate, urlVariables);
    }

    /**
     * @param contentType
     * @param content
     * @param urlTemplate
     * @param urlVariables
     * @return
     */
    public String putRequest(MediaType contentType, String content, String urlTemplate, Object... urlVariables) {
        return doRequest(RequestMethod.PUT, contentType, false, content, urlTemplate, urlVariables);
    }

    /**
     * @param contentType
     * @param content
     * @param urlTemplate
     * @param urlVariables
     * @return
     */
    public String putAsyncRequest(MediaType contentType, String content, String urlTemplate, Object... urlVariables) {
        return doRequest(RequestMethod.PUT, contentType, true, content, urlTemplate, urlVariables);
    }

    /**
     * @param content
     * @param urlTemplate
     * @param urlVariables
     * @return
     */
    public String putRequest(String content, String urlTemplate, Object... urlVariables) {
        return doRequest(RequestMethod.PUT, MediaType.APPLICATION_JSON, false, content, urlTemplate, urlVariables);
    }

    /**
     * @param content
     * @param urlTemplate
     * @param urlVariables
     * @return
     */
    public String putAsyncRequest(String content, String urlTemplate, Object... urlVariables) {
        return doRequest(RequestMethod.PUT, MediaType.APPLICATION_JSON, true, content, urlTemplate, urlVariables);
    }

    /**
     * @param urlTemplate
     * @param urlVariables
     * @return
     */
    public String deleteRequest(String urlTemplate, Object... urlVariables) {
        return doRequest(RequestMethod.DELETE, null, false, null, urlTemplate, urlVariables);
    }

    /**
     * @param urlTemplate
     * @param urlVariables
     * @return
     */
    public String deleteAsyncRequest(String urlTemplate, Object... urlVariables) {
        return doRequest(RequestMethod.DELETE, null, true, null, urlTemplate, urlVariables);
    }

    /**
     * @param filePath
     * @return
     */
    public String readJsonFile(String filePath) {
        BufferedReader bufferReader = null;
        try {
            File file = new File(filePath);
            long length = file.length();
            if (length > 5 * 1024 * 1024) {
                throw new IllegalArgumentException("试图读取的文件大小超过5M");
            }
            return IOUtils.toString(new FileInputStream(file), "UTF-8");
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new RuntimeException(filePath, e);
        } finally {
            try {
                if (null != bufferReader) {
                    bufferReader.close();
                }
            } catch (Exception e) {
            }
        }
    }

    /**
     * 
     * @param method
     * @param contentType
     * @param content
     * @param urlTemplate
     * @param urlVariables
     * @return
     */
    protected String doRequest(RequestMethod method, MediaType contentType, boolean async, String content, String urlTemplate, Object... urlVariables) {

        checkMappedController(urlTemplate);

        MockHttpServletRequestBuilder builder;
        switch (method) {
        case GET:
            builder = MockMvcRequestBuilders.get(urlTemplate, urlVariables);
            break;
        case POST:
            builder = MockMvcRequestBuilders.post(urlTemplate, urlVariables);
            break;
        case PUT:
            builder = MockMvcRequestBuilders.put(urlTemplate, urlVariables);
            break;
        case DELETE:
            builder = MockMvcRequestBuilders.delete(urlTemplate, urlVariables);
            break;
        default:
            throw new UnsupportedOperationException(method.name());
        }
        if (loginBefore && login(userName, password)) {
            builder.session(session);
        }
        if (content != null) {
            builder.contentType(contentType).content(content);
        }
        try {
            MvcResult mvcResult = mockMvc.perform(builder).andReturn();
            return async ? mvcResult.getAsyncResult().toString() : mvcResult.getResponse().getContentAsString();
        } catch (Exception e) {
            return hanldeRequestException(e, method, contentType, content, urlTemplate, urlVariables);
        }
    }

    /**
     * 上传文件
     * 
     * @param file
     *            文件域名称
     * @param path
     *            路由
     * @param urlTemplate
     * @param async
     *            是否是异步请求
     * @param urlVariables
     * @return
     */
    public String fileUpload(String file, String path, String urlTemplate, boolean async, Object... urlVariables) {
        checkMappedController(urlTemplate);
        MockMultipartHttpServletRequestBuilder builder = MockMvcRequestBuilders.fileUpload(urlTemplate, urlVariables);
        if (loginBefore && login(userName, password)) {
            builder.session(session);
        }
        try {
            builder.file(file, FileUtils.readFileToByteArray(new File(path)));
            MvcResult mvcResult = mockMvc.perform(builder).andReturn();
            return async ? mvcResult.getAsyncResult().toString() : mvcResult.getResponse().getContentAsString();
        } catch (Exception e) {
            return hanldeRequestException(e, RequestMethod.POST, null, null, urlTemplate, urlVariables);
        }
    }

    /**
     * @param e
     * @param method
     * @param contentType
     * @param content
     * @param urlTemplate
     * @param urlVariables
     * @return
     */
    protected String hanldeRequestException(Exception e, RequestMethod method, MediaType contentType, String content, String urlTemplate,
            Object... urlVariables) {
        return null;
    }

    /**
     * 登录
     * 
     * @param userName
     * @param password
     * @return
     * @throws Exception
     * @throws UnsupportedEncodingException
     */
    private boolean login(String userName, String password) {
        User user = new User(userName, password);
        MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.post("/users/login");
        builder.contentType(MediaType.APPLICATION_JSON).content(gson.toJson(user));
        String result = null;
        try {
            MvcResult mvc = mockMvc.perform(builder).andReturn();
            this.session = (MockHttpSession) mvc.getRequest().getSession();
            result = mvc.getResponse().getContentAsString();
        } catch (Exception e) {
            throw new IllegalStateException(String.format("用户名[%s],密码[%s]登录异常,请重新登录。", userName, password));
        }
        Assert.state(Boolean.parseBoolean(result), String.format("用户名[%s],密码[%s]登录失败,请验证用户名密码。", userName, password));
        this.loginBefore = false;
        return true;
    }

    /**
     * 校验请求的路由是否匹配指定的Controller,主要根据Controller上的@RequestMapping()来校验
     * 
     * @param urlTemplate
     */
    private void checkMappedController(String urlTemplate) {
        Assert.notNull(mappedController, "必须指明当前ControllerTest映射到哪个Controller");
        Class controllerClass = AopUtils.isAopProxy(mappedController) ? AopUtils.getTargetClass(mappedController) : mappedController.getClass();
        RequestMapping mapping = controllerClass.getAnnotation(RequestMapping.class);
        Assert.notNull(mapping, "mappedController必须含有[RequestMapping]注解");
        boolean mapped = false;
        for (String value : mapping.value()) {
            if (value.contains("{")) {
                value = value.substring(0, value.indexOf("{") + 1); // 当@RequestMapping("/user/{id}")形式时,截取"/user"
            }
            if (urlTemplate.startsWith(value)) {
                mapped = true;
                break;
            }
        }
        if (!mapped) {
            throw new CustomizedException(String.format("请求路由[%s]不匹配Controller:[%s]", urlTemplate, mappedController.getClass().getName()));
        }
    }

    /**
     * 模板方法,由子类重写以决定是否在运行之前登录
     */
    protected abstract void init();

}

使用方法:

package com.bob.test.controller;

import com.bob.config.mvc.model.CacheModel;
import com.bob.test.config.BaseControllerTest;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import com.bob.mvc.controller.RedisCacheController;
import com.google.gson.Gson;

/**
 * @since 2016年12月8日 下午5:16:52
 * @version $Id$
 * @author JiangJibo
 *
 */
public class StudentControllerTest extends BaseControllerTest {

    @Autowired //需要指定当前ControllerTest测试的是哪个Controller
    private RedisCacheController studentController;

    /* (non-Javadoc)
     * @see com.bob.test.config.BaseControllerTest#init()
     */
    @Override 
    protected void init() {
        super.mappedController = studentController;
        super.userName = "lanboal";
        super.password = "123456";
        //若需要在运行Controler测试前登陆,则需要在BaseControllerTest的login方法内指定你登陆的请求路径,
        //同时设置好登陆名及密码,这样在运行单元测试前会先执行登陆操作,然后将登录的SESSION传递给当前的测试用例,
        //当前测试时就能获取到用户的登录信息。
        super.loginBefore = true;
    }

    @Test
    public void testFormatDate() {
        String result = this.getRequest("/stus/date?date=1988-07-26", "");
        System.out.println("\t" + result);
    }

    @Test
    public void testListAll() throws Exception {
        //如果请求的是异步的,要求Controler的相应方法返回的对象时DeferredResult,Callable,WebAsyncTask这三个。
        String result = this.getAsyncRequest("/stus?mediaType=xml", "");
        System.out.println("\t" + result);
    }

    @Test
    public void testListByAge() throws Exception {
        String result = this.getRequest("/stus/age/27", "");
        System.out.println("\t" + result);
    }

    @Test
    public void testCreate() {
        CacheModel sutdent = new CacheModel();
        sutdent.setId(10);
        sutdent.setAge(30);
        sutdent.setAdress("金华");
        sutdent.setTelephone("1748568745");
        this.postRequest(new Gson().toJson(sutdent), "/stus", "");
    }

}

你可能感兴趣的:(spring,junit,造轮子)