我是靠谱客的博主 热情猫咪,最近开发中收集的这篇文章主要介绍分析MockHttpServletRequestBuilder中content和param的区别,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

最近在做一个自动测试的平台,使用的是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中进行读取。

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

最后

以上就是热情猫咪为你收集整理的分析MockHttpServletRequestBuilder中content和param的区别的全部内容,希望文章能够帮你解决分析MockHttpServletRequestBuilder中content和param的区别所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(50)

评论列表共有 0 条评论

立即
投稿
返回
顶部