背景
在我們經(jīng)常開發(fā)的時候,通常我們都會把時間花費在接口聯(lián)調(diào)和等待接口階段。作為開發(fā)人員我應(yīng)該自己做出單元測試,但是這并不是我今天要描述的范圍,今天我只要是以在后臺接口還沒有開發(fā)完成的階段,協(xié)調(diào)測試先給出數(shù)據(jù)的響應(yīng)格式,從而開發(fā)人員自己Mock 數(shù)據(jù)。以此,開發(fā)接下的流程。的確,在前一兩年我還是自己搭建Tomcat 然后在自己的本地服務(wù)器存放自己需要Mock 解析的Json 文件。以此達到這樣的目的,但是這樣是存在一個問題,那就是接口的入?yún)?,在此就需要作出校驗,很顯然我們對這樣的方式,表示不認同。所以,有了以下的內(nèi)容。
簡介
由于項目的網(wǎng)絡(luò)框架是使用的是Retrofit+RxJava從而在實現(xiàn)上,有很大的便利。需要注意的是Retrofit是對于Okhttp 的再優(yōu)化和封裝。看到Okhttp 有沒有想到什么。對的他有很強大的功能那就是Interceptor(攔截器)。
我們需要了解一下的幾點:
Interceptor
OkHttp 可在 Request 和 Response 中設(shè)置任意個數(shù)的 Intercepor。對請求體和響應(yīng)體進行處理。借助 OkHttp Interceptor 機制,創(chuàng)建一個 MockIntercepor,模擬返回一個 Response。當然他不只可以在Request、Response設(shè)置攔截,并且還可以設(shè)置網(wǎng)絡(luò)狀態(tài)的攔截、Header、等等。不在一一的贅述。如果你還不是足夠的了解他的原理和使用方式,你可以觀看一下的介紹https://github.com/square/okhttp/wiki/Interceptors
1. HeaderInterceptor
統(tǒng)一配置請求頭,無需直接在業(yè)務(wù)封裝層進行相關(guān)配置。減少代碼的耦合性。
/**
* 設(shè)置請求Header
*
*/
public class HeaderInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request.Builder builder = request.newBuilder();
builder.addHeader("-Header", creatHeader())
.addHeader("user-agent", "公司名稱/應(yīng)用名稱")
.build();
Request newRequest = builder.build();
return chain.proceed(newRequest);
}
/**
* Request Header
* <p> 由于sign 與 URL 關(guān)聯(lián)因此,它可理解為動態(tài)的參數(shù),而不能理解為固定參數(shù)</p>
*
* @return
*/
public String creatHeader() {
StringBuffer header = new StringBuffer();
header.append("platform").append("=").append("android").append(";")
.append("os").append("=").append(Build.VERSION.SDK_INT).append(";")
.append("appid").append("=").append("com.xxx.xxx").append(";")
.append("version").append("=").append("2320").append(";")
.append("mid").append("=").append(Build.MODEL.replaceAll(" ", "_")).append(";")
.append("channel").append("=").append("ceshi");// 使用gradle 語法進行獲取不同的渠道配置
return header.toString();
}
}
2. MockDataIntercepter
在這里可能需要解釋的是,因為我們在Mock 數(shù)據(jù)的時候,其實是直接跳過請求參數(shù)的配置,也就是說我們需要攔截Resphone 進行攔截。如果你使用了RxJava 操作符的類型轉(zhuǎn)義,這時候你就需要在gradle 中配置在Debug 狀態(tài)下不在配置RxJavaCallAdapterFactory。因為我只是在Debug狀態(tài)下進行Mock 數(shù)據(jù),所以在gradle 文件中配置變量,使其注入到BuildConfig 類型當中。已提供給項目全局使用,retrofitBuilder.addCallAdapterFactory(RxJavaCallAdapterFactory.create()); 具體配置如下:
public class MockDataIntercepter implements Interceptor {
private final String responeJsonPath;
public MockDataIntercepter(String responeJsonPath) {
this.responeJsonPath = responeJsonPath;
}
@Override
public Response intercept(Chain chain) throws IOException {
String responseString = createResponseBody(chain);
//Response 配置
Response response = new Response.Builder()
.code(200)
.message(responseString)
.request(chain.request())
.protocol(Protocol.HTTP_1_0)
.body(ResponseBody.create(MediaType.parse("application/json"), responseString.getBytes()))
.addHeader("content-type", "application/json")
.build();
return response;
}
/**
* 該方法是為動態(tài)的配置各個接口數(shù)據(jù),為此,需要對各個接口的注解,進行
* 攔截處理,以實現(xiàn)加載不同的json數(shù)據(jù)
* @param chain
* @return
*/
private String createResponseBody(Chain chain) {
String responseString = null;
HttpUrl httpUrl = chain.request().url();
String urlPath = httpUrl.url().toString();
//url 匹配形式進行數(shù)據(jù)返回
// if (urlPath.matches("^(/users/)+[^/]+(/login)$")) {//匹配/users/{username}/login
// responseString = getResponseString("users_login.json");
// } else if (urlPath.matches("^(/users/)+[^/]*+$")) {//匹配/users/{username}
// responseString = getResponseString("test.json");
// }
// 直接使用文件進行數(shù)據(jù)返回,不提倡。沒有針對性
return FileUtils.testCase;
}
private String getResponseString(String fileName) {
return FileUtils.readFile(responeJsonPath +fileName,"UTF-8");
}
}
當然使用這樣的方式不僅能夠?qū)崿F(xiàn)這樣兩種的配置。我們進行網(wǎng)絡(luò)的訪問的時候通常會攜帶一些固定的參數(shù),如version、os、platform 等,我們也可以針對固定參數(shù)的一些配置同樣適用。再次就不在過多的贅述了。