背景
在我们经常开发的时候,通常我们都会把时间花费在接口联调和等待接口阶段。作为开发人员我应该自己做出单元测试,但是这并不是我今天要描述的范围,今天我只要是以在后台接口还没有开发完成的阶段,协调测试先给出数据的响应格式,从而开发人员自己Mock 数据。以此,开发接下的流程。的确,在前一两年我还是自己搭建Tomcat 然后在自己的本地服务器存放自己需要Mock 解析的Json 文件。以此达到这样的目的,但是这样是存在一个问题,那就是接口的入参,在此就需要作出校验,很显然我们对这样的方式,表示不认同。所以,有了以下的内容。
简介
由于项目的网络框架是使用的是Retrofit+RxJava从而在实现上,有很大的便利。需要注意的是Retrofit是对于Okhttp 的再优化和封装。看到Okhttp 有没有想到什么。对的他有很强大的功能那就是Interceptor(拦截器)。
我们需要了解一下的几点:
Interceptor
OkHttp 可在 Request 和 Response 中设置任意个数的 Intercepor。对请求体和响应体进行处理。借助 OkHttp Interceptor 机制,创建一个 MockIntercepor,模拟返回一个 Response。当然他不只可以在Request、Response设置拦截,并且还可以设置网络状态的拦截、Header、等等。不在一一的赘述。如果你还不是足够的了解他的原理和使用方式,你可以观看一下的介绍https://github.com/square/okhttp/wiki/Interceptors
1. HeaderInterceptor
统一配置请求头,无需直接在业务封装层进行相关配置。减少代码的耦合性。
/**
* 设置请求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", "公司名称/应用名称")
.build();
Request newRequest = builder.build();
return chain.proceed(newRequest);
}
/**
* Request Header
* <p> 由于sign 与 URL 关联因此,它可理解为动态的参数,而不能理解为固定参数</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 数据的时候,其实是直接跳过请求参数的配置,也就是说我们需要拦截Resphone 进行拦截。如果你使用了RxJava 操作符的类型转义,这时候你就需要在gradle 中配置在Debug 状态下不在配置RxJavaCallAdapterFactory。因为我只是在Debug状态下进行Mock 数据,所以在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;
}
/**
* 该方法是为动态的配置各个接口数据,为此,需要对各个接口的注解,进行
* 拦截处理,以实现加载不同的json数据
* @param chain
* @return
*/
private String createResponseBody(Chain chain) {
String responseString = null;
HttpUrl httpUrl = chain.request().url();
String urlPath = httpUrl.url().toString();
//url 匹配形式进行数据返回
// if (urlPath.matches("^(/users/)+[^/]+(/login)$")) {//匹配/users/{username}/login
// responseString = getResponseString("users_login.json");
// } else if (urlPath.matches("^(/users/)+[^/]*+$")) {//匹配/users/{username}
// responseString = getResponseString("test.json");
// }
// 直接使用文件进行数据返回,不提倡。没有针对性
return FileUtils.testCase;
}
private String getResponseString(String fileName) {
return FileUtils.readFile(responeJsonPath +fileName,"UTF-8");
}
}
当然使用这样的方式不仅能够实现这样两种的配置。我们进行网络的访问的时候通常会携带一些固定的参数,如version、os、platform 等,我们也可以针对固定参数的一些配置同样适用。再次就不在过多的赘述了。
网友评论