http接口测试总结

1、  使用HttpClient发送Get/Post请求

a)         Get请求

代码示例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public static String getHttpResponse4Get()
  
{
  
        String url = “http: //www.tmall.com/test.do?id=123”;
  
        GetMethod httpGet = new GetMethod(url);
  
        httpGet.addRequestHeader( "content-type" , "text/html; charset=gbk" );
  
        httpGet.getParams().setParameter( "http.socket.timeout" , 20000 );
  
        try {
  
            // 设置成了默认的恢复策略,在发生异常时候将自动重试3次,在这里你也可以设置成自定义的恢复策略
  
            httpGet.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
  
                   new DefaultHttpMethodRetryHandler());
  
            if (httpClient.executeMethod(httpGet) != HttpStatus.SC_OK) {
  
               System.out.println( "httpGet(\"" + url + "\") failed: \n"
  
                      + httpGet.getStatusLine());
  
               return null ;
  
            }
  
            return httpGet.getResponseBodyAsString();
  
        } catch (Exception e) {
  
            System.out.println( "httpGet(\"" + url + "\") failed: \n" + e.getMessage());
  
            return null ;
  
        } finally {
  
            httpGet.releaseConnection();
  
            httpClient = null ;
  
        }
  
}

注意点:

1、传入参数值(或者参数串)需要进行encode,虽然httpClient中是有用URLCodec.encodeUrl()进行encode,但我实验发现,和URLEncoder.encode()进行encode的结果还是有区别,会对最终响应有影响,所以建议自行encode;
2、需要判断请求返回的状态码是否为200以后获取到的响应才是可靠的;
3、最终要释放掉链接,做好收尾工作。

b)         Post请求

代码示例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public static String getHttpResponse4Post()
  
{
  
     try
  
         HttpClient client = new DefaultHttpClient(); 
  
         HttpPost request = new HttpPost( "http://www.tmall.com/test.do" ); 
  
         //使用NameValuePair来保存要传递的Post参数 
  
         List postParameters = new ArrayList(); 
  
         //添加要传递的参数   
  
         postParameters.add( new BasicNameValuePair( "id" , "12345" )); 
  
         postParameters.add( new BasicNameValuePair( "username" , "dave" )); 
  
         //实例化UrlEncodedFormEntity对象 
  
         UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity( 
  
                 postParameters); 
  
         //使用HttpPost对象来设置UrlEncodedFormEntity的Entity 
  
         request.setEntity(formEntity); 
  
         HttpResponse response = client.execute(request); 
  
         if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
  
               String s = EntityUtils.toString(response.getEntity(), "utf-8" );
  
               System.out.println(s);
  
               System.out.println( "请求正常,结束http请求" );
  
               return s;
  
            }
  
        } catch (Exception e) {
  
            System.out.println( "请求发生异常,异常信息抛出" );
  
            e.printStackTrace();
  
        } finally {
  
            httpClient.getConnectionManager().shutdown();
  
        }
  
        return "" ;
  
}

c)         在线上环境发送get请求

要将在daily下运行的http接口测试脚本放到线上运行,需要做如下一些操作:

1、         建立一个真实的登录session:发送post请求到:https://login.taobao.com/member/login.jhtml

2、         然后发送get请求到http://i.taobao.com/my_taobao.htm从缓存中同步一次cookie

3、         通过this.httpClientLogin.getState().getCookies();获取到cookie信息,然后解析到_tb_token_的值

4、         把这个_tb_token_这个参数和值附加到测试请求的url中,通过get方式进行请求即可

5、         注意:在登录的post参数设置时,需要将字符集设为:GBK

?
1
postMethod.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "GBK" );

如果改为utf-8或者不set此param就可能导致获取的cookie值不足的问题

(本部分感谢浣碧同学的悉心指点!)

 

2、  urlencode/urldecode

为什么url需要encode以后才能发送,是因为URL需要转化为ASCII字符集才能在被HTTP协议使用。ASCII字符集7位的字符集,包含128个字符,其中常见的有数字1-9,还有a-zA-Z以及一些特殊字符。当URL中包含非ASCII字符集的字符的时候,就需要encode为ASCII字符集,以便通过HTTP协议发送请求

Java中进行URL Encode和Decode的方法是:

?
1
2
3
URLEncoder.encode(valueOfUrlParam, "UTF-8" );
  
URLDecoder.decode(urlParamStr, "UTF-8" );

两个类都来自java.net的包,平时可以使用online的encode/decode网站进行操作

这里需要注意的是:

  • 只能对URL的参数进行encode(可以把整个参数串进行encode,也可以只对参数值进行encode,不能对域名和URI进行encode,例如:

http://www.tmall.com/test.do?id=123,234,正确的encode以后的url为:

http://www.tmall.com/test.do?id%3d123%2c234 或者:

http://www.tmall.com/test.do?id=123%2c234

  • 在用post发请求的时候,需要将参数内容组装成HttpEntity然后set到post对象中,此时会用到UrlEncodedFormEntity这个类,这类的构造函数里会把post的参数进行一次encode,所以自己不需要额外进行一次encode,否则应用服务器在一次decode情况下就会读取错误的参数值

3、  mock

a)         参数mock

问题场景:在服务端应用程序里通常会有这样的片段:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static Long getLoginUserId(TurbineRunData rundata) {
 
         String userId = ( String ) rundata.getRequest().getSession().getAttribute(
 
                 SessionKeeper.ATTRIBUTE_USER_ID_NUM);
 
         if (StringUtils.isNumeric(userId)) {
 
             return Long.parseLong(userId);
 
         }
 
         return null ;
 
}
?
1
2
3
4
5
6
7
8
9
if (userId== null || userId <= 0 ) {
  
       result.setSuccess( false );
  
       result.setErrorCode(MallBrandResultCode.USER_NOT_LOGIN);
  
       result.setErrorMsg( "参数user_id缺失" );
  
}

如果webx不能从session中获取到userID,那就会被业务逻辑控制住,不能继续往下走,解决办法有两个:

l  往session里塞userId

要实现这种方案,首先需要创建一个真实daily下用户登录的session,由于是在daily下,还需要解决安全认证的问题,这样便能解决这个问题。但明显这样做的成本太高,而且不是很必要。

l  通过get参数mock掉这段代码逻辑

和开发约定一个参数和参数值,在程序中判断如果有这个参数值则直接返回一个指定的userId。

?
1
boolean test = rundata.getParameters().getBoolean( "test" , false );

b)         压缩mock

为了防止前端发送的json数据时http的get请求超长,前后端开发通过7zip进行压缩,但httpClient认为这样的压缩过的请求是BadRequest,所以只能试图把请求换成post,同时把解压缩的逻辑mock掉,以便于daily下的接口测试。具体详见:《http接口测试中有关URL长度限制的问题(Maximum URL Length)》

c)         csrf控制mock

代码中为了防止csrf攻击,都会加入csrf的控制模块,在daily下可以直接让开发把这段逻辑注释掉,但如果脚本还要在系统上线后回归,那就需要和开发一起把这段逻辑mock掉,以简化测试应用的复杂度,降低测试脚本开发难度。

你可能感兴趣的:(接口测试,HttpClient)