1. 程式人生 > >http介面測試總結

http介面測試總結

1、使用HttpClient傳送Get/Post請求
a)Get請求
程式碼示例:

	public static String getHttpResponse4Get() { 		
		CloseableHttpClient httpclient = HttpClients.createDefault();
		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請求
程式碼示例:

public static String getHttpResponse4Post() {
		try {
			HttpClient client = new DefaultHttpClient();
			HttpPost request = new HttpPost("http://www.tmall.com/test.do");
			// 使用NameValuePair來儲存要傳遞的Post引數
			List<NameValuePair> postParameters = new ArrayList<NameValuePair>();
			// 新增要傳遞的引數
			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

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的方法是:

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
問題場景:在服務端應用程式裡通常會有這樣的片段:

	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;
	}
	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。

b)壓縮mock
為了防止前端傳送的json資料時http的get請求超長,前後端開發通過7zip進行壓縮,但httpClient認為這樣的壓縮過的請求是BadRequest,所以只能試圖把請求換成post,同時把解壓縮的邏輯mock掉,以便於daily下的介面測試。具體詳見:《http介面測試中有關URL長度限制的問題(Maximum URL Length)》
c)csrf控制mock
程式碼中為了防止csrf攻擊,都會加入csrf的控制模組,在daily下可以直接讓開發把這段邏輯註釋掉,但如果指令碼還要在系統上線後迴歸,那就需要和開發一起把這段邏輯mock掉,以簡化測試應用的複雜度,降低測試指令碼開發難度。