分析MockHttpServletRequestBuilder中content和param的区别

来源:互联网 发布:淘宝装修主页 编辑:程序博客网 时间:2024/06/03 00:27

最近在做一个自动测试的平台,使用的是Spring的自带测试库。如何使用,这里不再说了,网上有很多,推荐开涛写的博客

我的主要测试代码:

//主要构造mock请求类,可以不用看try {            for(TestClass tmpClass:classes){                List<TestUrl> urls = tmpClass.getUrls();                for(TestUrl url:urls){                    String urlString = url.getCompositeUrl();                    MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get(urlString);                    initRequestParams(requestBuilder,url);                    mockMvc.perform(requestBuilder).andDo(MockMvcResultHandlers.print());                }            }        } catch (Exception e) {            e.printStackTrace();        }//初始化request参数private void initRequestParams(MockHttpServletRequestBuilder builder,TestUrl url) {        //设置编码格式        builder.characterEncoding("utf-8");        TestParameter parameter = url.getParamter();        TestContent content = url.getContent();        TestSession sessionData = url.getSession();        //添加session        if(sessionData != null){            MockHttpSession mockHttpSession = new MockHttpSession();            Map<String, Object> maps = sessionData.getSession();            Set<Map.Entry<String, Object>> sets = maps.entrySet();            for(Map.Entry<String, Object> entry:sets){                mockHttpSession.setAttribute(entry.getKey(), entry.getValue());            }            builder.session(mockHttpSession);        }        if(parameter != null){            Map<String, String> paramMaps = parameter.getParams();            Set<Map.Entry<String, String>> sets = paramMaps.entrySet();            StringBuilder paramBuilder = new StringBuilder();            for(Map.Entry<String, String> entry:sets){                paramBuilder.append('&');                paramBuilder.append(entry.getKey());                paramBuilder.append('=');                paramBuilder.append(entry.getValue());            }            String bodyData = paramBuilder.deleteCharAt(0).toString();            System.out.println(bodyData);            builder.content(bodyData);//这里是重点            builder.contentType(MediaType.APPLICATION_FORM_URLENCODED);//这里是重点//          for(Map.Entry<String, String> entry:sets){//              builder.param(entry.getKey(), entry.getValue());//          }            return;        }    }

根据HTTP协议,当body中参数以form表单格式进行提交时,在服务器端通过request.getParameter(“name”)来获取是可以获取到的,效果和在Url中使用参数是一样的。然而当我在这里设置参数时发现是有问题的,test结果显示缺少参数,而缺少的参数是在body里面的,这说明mock并没有content-type类型去解析content的数据。

于是我查看了Spring中MockHttpServletRequestBuilder的源码

...private String contentType;//content类型private byte[] content;//content数据private final MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>();//参数列表....    /**     * Set the request body as a UTF-8 String.     * @param content the body content     */    public MockHttpServletRequestBuilder content(String content) {        try {            this.content = content.getBytes("UTF-8");        }        catch (UnsupportedEncodingException e) {            // should never happen        }        return this;    }/**     * Add a request parameter to the {@link MockHttpServletRequest}.     * <p>If called more than once, new values get added to existing ones.     * @param name the parameter name     * @param values one or more values     */    public MockHttpServletRequestBuilder param(String name, String... values) {        addToMultiValueMap(this.parameters, name, values);//将name和value添加到parameter中,允许一个名字对应多个value值        return this;    }Ok,以上是初始化的方法。下面是重点,builder的最终目的是build一个MockHttpServletRequest,而这个工作是有buildRequest()方法来完成的。部分:try {            if (this.url.getRawQuery() != null) {                request.setQueryString(this.url.getRawQuery());            }            MultiValueMap<String, String> queryParams =                    UriComponentsBuilder.fromUri(this.url).build().getQueryParams();            for (Entry<String, List<String>> entry : queryParams.entrySet()) {                for (String value : entry.getValue()) {                    value = (value != null) ? UriUtils.decode(value, "UTF-8") : null;                    request.addParameter(UriUtils.decode(entry.getKey(), "UTF-8"), value);                }            }        }        catch (UnsupportedEncodingException ex) {            // shouldn't happen        }        for (String name : this.parameters.keySet()) {            for (String value : this.parameters.get(name)) {                request.addParameter(name, value);            }        }        request.setContentType(this.contentType);        request.setContent(this.content);        request.setCharacterEncoding(this.characterEncoding);

由buildRequest的代码可以发现,Mock将URL的参数和通过使用param添加的参数添加到request中的parameter中了,而将content内容、类型并没有进行解析,直接添加到request的content中了。

让我们再查看MockHttpServletRequest的代码:

@Override    public String getParameter(String name) {        String[] arr = (name != null ? this.parameters.get(name) : null);        return (arr != null && arr.length > 0 ? arr[0] : null);    }

MockHttpServletRequest实现了HttpServletRequest,而在getParameter进行了重写,即从parameter的map中进行读取。

这也就解释了文章开头提出的问题。

0 0