前言

前面基本都是接口后端类的测试,这章聊一下web端的http服务如何测试。

我们使用junit测试web的时候不得不起一个完整的服务后调用才能够进入controller代码里面,就如下代码:

@Controller
@RequestMapping
public class WarehouseController {
	@RequestMapping(value = "/web/warehouse/httpDownload")
    public ResponseEntity<String> httpDownload(
    	HttpServletRequest request,
       	HttpServletResponse response,
       	@RequestParam(name = "content", defaultValue = "") String content,
       	@RequestParam(name = "downloadToken", defaultValue = "") String downloadToken,
       	@RequestParam(name = "systemCode", defaultValue = "") String systemCode) {
       	//todo...
    }

    @RequestMapping(value = "/web/warehouse/httpUpload")
    public ResponseEntity<String> httpUpload(
    	HttpServletRequest request,
       	HttpServletResponse response,
        @RequestParam(name = "file") MultipartFile file) {
       	//todo...
    }
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
//由于是Web项目,Junit需要模拟ServletContext,因此我们需要给我们的测试类加上@WebAppConfiguration。
@WebAppConfiguration
public class WarehouseControllerTest {

    @Autowired
    private WebApplicationContext webApplicationContext;
    private MockMvc mockMvc;

    @Before
    public void setUp() throws Exception {
        //指定WebApplicationContext,将会从该上下文获取相应的控制器并得到相应的MockMvc;
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }
  	
  	@Test
    public void httpDownload() {
        String content = "xxx";
        String systemCode = "xxx";
        String token = "xxx";
        try {
            MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/httpDownload")
                    //contentType参数指定时要注意对应的接受协议类型
                    .contentType(MediaType.APPLICATION_JSON_UTF8)
                    .accept(MediaType.APPLICATION_JSON_UTF8)
                    .param("content", content)
                    .param("systemCode", systemCode)
                    .param("downloadToken", md5))
                    .andExpect(MockMvcResultMatchers.status().isOk())
                    .andDo(MockMvcResultHandlers.print())
                    .andReturn();
            System.out.println(mvcResult.getResponse().getContentAsString());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

这时候问题就是如果启动整个web应用非常慢,依赖外部存储资源等又非常多,那么该测试会给我们造成非常大的阻碍。

分片测试法

所谓分片测试法是指我只让单元测试只模拟启动我所要测试的controller类即可,其他的一概不加载。

import org.apache.commons.io.FileUtils;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
//注解全部都不用
public class WarehouseControllerTest {
    private MockMvc mockMvc;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
      	//通过MockMvcBuilders.standaloneSetup模拟一个Mvc测试环境,通过build得到一个MockMvc
        mockMvc = MockMvcBuilders.standaloneSetup(new WarehouseController()).build();
    }
  
  	@Test
    public void httpUpload() {
        try {
          	//第一个参数要和Controller里面的@RequestParam MultipartFile指定名称一致
          	MockMultipartFile firstFile = new MockMultipartFile("file", 
                    "filename.txt", "text/plain", "some xml".getBytes());
            MvcResult mvcResult = mockMvc.perform(
              	//调用地址,带文件的方式用multipart
            		MockMvcRequestBuilders.multipart("/web/warehouse/httpUpload")
                            .file(firstFile)
              	//一些传输协议参数
              	//multipart方法里有这个,这里不需要再额外指定.contentType(MediaType.APPLICATION_JSON_UTF8)
              	.accept(MediaType.APPLICATION_JSON_UTF8)
              	//body参数
              	.param("myBody", "xxxx")
              	//头信息
              	.header("myHeader", "{}"))
             //调用接口状态判断,等于一个断言器
             .andExpect(MockMvcResultMatchers.status().isOk())
             .andDo(MockMvcResultHandlers.print())
             .andReturn();
          
          	//有返回值这里获取
            System.out.println(mvcResult.getResponse().getContentAsString());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

以上是测试上传和下载文件的方法,这个个例子涵盖了所有的传参和传参类型,是否有返回值等情况,消息体放body还是header例子都包含了。

而且上传文件也不依赖本地的某个文件指定,直接就能模拟一个文件出来。最重要的是脱离了依赖启动整个web容器。