Ale*_*mes 90 testing android mocking retrofit mockwebserver
在使用方形改造框架时,模拟服务器进行测试的最佳方法是什么.
潜在方式:
创建一个新的改造客户端并将其设置在RestAdapter.Builder().setClient()中.这涉及解析Request对象并将json作为Response对象返回.
将此带注释的接口实现为模拟类,并使用它来代替RestAdapter.create()提供的版本(不要测试gson序列化)
?
理想情况下,我希望模拟服务器提供json响应,以便我可以同时测试gson序列化.
任何例子都将非常感谢.
Vic*_*yan 97
由于创建MockClient类和实现它的旧机制Client不再适用于Retrofit 2.0,在这里我描述了一种新的方法.您现在需要做的就是为OkHttpClient添加自定义拦截器,如下所示.FakeInterceptorclass只是覆盖intercept方法,如果应用程序处于DEBUG模式返回给定JSON.
public final class RestClient {
private static IRestService mRestService = null;
public static IRestService getClient() {
if(mRestService == null) {
final OkHttpClient client = new OkHttpClient();
// ***YOUR CUSTOM INTERCEPTOR GOES HERE***
client.interceptors().add(new FakeInterceptor());
final Retrofit retrofit = new Retrofit.Builder()
// Using custom Jackson Converter to parse JSON
// Add dependencies:
// com.squareup.retrofit:converter-jackson:2.0.0-beta2
.addConverterFactory(JacksonConverterFactory.create())
// Endpoint
.baseUrl(IRestService.ENDPOINT)
.client(client)
.build();
mRestService = retrofit.create(IRestService.class);
}
return mRestService;
}
}
Run Code Online (Sandbox Code Playgroud)
public interface IRestService {
String ENDPOINT = "http://www.vavian.com/";
@GET("/")
Call<Teacher> getTeacherById(@Query("id") final String id);
}
Run Code Online (Sandbox Code Playgroud)
public class FakeInterceptor implements Interceptor {
// FAKE RESPONSES.
private final static String TEACHER_ID_1 = "{\"id\":1,\"age\":28,\"name\":\"Victor Apoyan\"}";
private final static String TEACHER_ID_2 = "{\"id\":1,\"age\":16,\"name\":\"Tovmas Apoyan\"}";
@Override
public Response intercept(Chain chain) throws IOException {
Response response = null;
if(BuildConfig.DEBUG) {
String responseString;
// Get Request URI.
final URI uri = chain.request().url().uri();
// Get Query String.
final String query = uri.getQuery();
// Parse the Query String.
final String[] parsedQuery = query.split("=");
if(parsedQuery[0].equalsIgnoreCase("id") && parsedQuery[1].equalsIgnoreCase("1")) {
responseString = TEACHER_ID_1;
}
else if(parsedQuery[0].equalsIgnoreCase("id") && parsedQuery[1].equalsIgnoreCase("2")){
responseString = TEACHER_ID_2;
}
else {
responseString = "";
}
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();
}
else {
response = chain.proceed(chain.request());
}
return response;
}
}
Run Code Online (Sandbox Code Playgroud)
GitHub项目的源代码
Ale*_*mes 82
我决定尝试方法1如下
public class MockClient implements Client {
@Override
public Response execute(Request request) throws IOException {
Uri uri = Uri.parse(request.getUrl());
Log.d("MOCK SERVER", "fetching uri: " + uri.toString());
String responseString = "";
if(uri.getPath().equals("/path/of/interest")) {
responseString = "JSON STRING HERE";
} else {
responseString = "OTHER JSON RESPONSE STRING";
}
return new Response(request.getUrl(), 200, "nothing", Collections.EMPTY_LIST, new TypedByteArray("application/json", responseString.getBytes()));
}
}
Run Code Online (Sandbox Code Playgroud)
并使用它:
RestAdapter.Builder builder = new RestAdapter.Builder();
builder.setClient(new MockClient());
Run Code Online (Sandbox Code Playgroud)
它运行良好,允许您测试您的json字符串,而无需联系真实的服务器!
Jak*_*ton 20
测试对象的JSON反序列化(可能是TypeAdapters?)似乎是一个单独的问题,需要单独的单元测试.
我亲自使用版本2.它提供了类型安全,重构友好的代码,可以轻松调试和更改.毕竟,如果你没有为测试创建它们的替代版本,那么将API声明为接口有什么用呢!胜利的多态性.
另一种选择是使用Java Proxy.这实际上是Retrofit(当前)实现其底层HTTP交互的方式.这无疑需要更多的工作,但可以实现更加动态的模拟.
在转移到真正的服务器之前,我是Apiary.io的忠实粉丝,用于模拟 API.
您还可以使用flat .json文件并从文件系统中读取它们.
您还可以使用Twitter,Flickr等可公开访问的API.
以下是一些关于Retrofit的其他重要资源.
幻灯片:https://docs.google.com/presentation/d/12Eb8OPI0PDisCjWne9-0qlXvp_-R4HmqVCjigOIgwfY/edit#slide=id.p
视频:http://www.youtube.com/watch?v = UtM06W51pPw&feature = g-user-u
示例项目:https://github.com/dustin-graham/ucad_twitter_retrofit_sample
小智 7
首先,创建您的Retrofit界面.
public interface LifeKitServerService {
/**
* query event list from server,convert Retrofit's Call to RxJava's Observerable
*
* @return Observable<HttpResult<List<Event>>> event list from server,and it has been convert to Obseverable
*/
@GET("api/event")
Observable<HttpResult<List<Event>>> getEventList();
}
Run Code Online (Sandbox Code Playgroud)您的请求者如下:
public final class HomeDataRequester {
public static final String TAG = HomeDataRequester.class.getSimpleName();
public static final String SERVER_ADDRESS = BuildConfig.DATA_SERVER_ADDR + "/";
private LifeKitServerService mServerService;
private HomeDataRequester() {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
//using okhttp3 interceptor fake response.
.addInterceptor(new MockHomeDataInterceptor())
.build();
Retrofit retrofit = new Retrofit.Builder()
.client(okHttpClient)
.baseUrl(SERVER_ADDRESS)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(new Gson()))
.build();
//using okhttp3 inteception to fake response.
mServerService = retrofit.create(LifeKitServerService.class);
//Second choice,use MockRetrofit to fake data.
//NetworkBehavior behavior = NetworkBehavior.create();
//MockRetrofit mockRetrofit = new MockRetrofit.Builder(retrofit)
// .networkBehavior(behavior)
// .build();
//mServerService = new MockLifeKitServerService(
// mockRetrofit.create(LifeKitServerService.class));
}
public static HomeDataRequester getInstance() {
return InstanceHolder.sInstance;
}
public void getEventList(Subscriber<HttpResult<List<Event>>> subscriber) {
mServerService.getEventList()
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
}
Run Code Online (Sandbox Code Playgroud)如果你使用第二种选择(使用Retrofit接口来模拟服务器数据),你需要MockRetrofit,使用代码如下:
public final class MockLifeKitServerService implements LifeKitServerService {
public static final String TAG = MockLifeKitServerService.class.getSimpleName();
private BehaviorDelegate<LifeKitServerService> mDelegate;
private Gson mGson = new Gson();
public MockLifeKitServerService(BehaviorDelegate<LifeKitServerService> delegate) {
mDelegate = delegate;
}
@Override
public Observable<HttpResult<List<Event>>> getEventList() {
List<Event> eventList = MockDataGenerator.generateEventList();
HttpResult<List<Event>> httpResult = new HttpResult<>();
httpResult.setCode(200);
httpResult.setData(eventList);
LogUtil.json(TAG, mGson.toJson(httpResult));
String text = MockDataGenerator.getMockDataFromJsonFile("server/EventList.json");
if (TextUtils.isEmpty(text)) {
text = mGson.toJson(httpResult);
}
LogUtil.d(TAG, "Text:\n" + text);
text = mGson.toJson(httpResult);
return mDelegate.returningResponse(text).getEventList();
}
Run Code Online (Sandbox Code Playgroud)4.我的数据来自资产文件(Asset/server/EventList.json),这个文件内容是:
{
"code": 200,
"data": [
{
"uuid": "e4beb3c8-3468-11e6-a07d-005056a05722",
"title": "title",
"image": "http://image.jpg",
"goal": 1500000,
"current": 51233,
"hot": true,
"completed": false,
"createdAt": "2016-06-15T04:00:00.000Z"
}
]
}
Run Code Online (Sandbox Code Playgroud)
5.如果你使用的是okhttp3拦截器,你需要自定义拦截器,如下所示:
public final class MockHomeDataInterceptor implements Interceptor {
public static final String TAG = MockHomeDataInterceptor.class.getSimpleName();
@Override
public Response intercept(Chain chain) throws IOException {
Response response = null;
String path = chain.request().url().uri().getPath();
LogUtil.d(TAG, "intercept: path=" + path);
response = interceptRequestWhenDebug(chain, path);
if (null == response) {
LogUtil.i(TAG, "intercept: null == response");
response = chain.proceed(chain.request());
}
return response;
}
private Response interceptRequestWhenDebug(Chain chain, String path) {
Response response = null;
if (BuildConfig.DEBUG) {
Request request = chain.request();
if (path.equalsIgnoreCase("/api/event")) {
//get event list
response = getMockEventListResponse(request);
}
}
private Response getMockEventListResponse(Request request) {
Response response;
String data = MockDataGenerator.getMockDataFromJsonFile("server/EventList.json");
response = getHttpSuccessResponse(request, data);
return response;
}
private Response getHttpSuccessResponse(Request request, String dataJson) {
Response response;
if (TextUtils.isEmpty(dataJson)) {
LogUtil.w(TAG, "getHttpSuccessResponse: dataJson is empty!");
response = new Response.Builder()
.code(500)
.protocol(Protocol.HTTP_1_0)
.request(request)
//protocol&request be set,otherwise will be exception.
.build();
} else {
response = new Response.Builder()
.code(200)
.message(dataJson)
.request(request)
.protocol(Protocol.HTTP_1_0)
.addHeader("Content-Type", "application/json")
.body(ResponseBody.create(MediaType.parse("application/json"), dataJson))
.build();
}
return response;
}
}
Run Code Online (Sandbox Code Playgroud)
6.最后,您可以向您的服务器请求代码:
mHomeDataRequester.getEventList(new Subscriber<HttpResult<List<Event>>>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
LogUtil.e(TAG, "onError: ", e);
if (mView != null) {
mView.onEventListLoadFailed();
}
}
@Override
public void onNext(HttpResult<List<Event>> httpResult) {
//Your json result will be convert by Gson and return in here!!!
});
}
Run Code Online (Sandbox Code Playgroud)
谢谢阅读.
添加到@Alec的答案,我扩展了模拟客户端,直接从资产文件夹中的文本文件获取响应,具体取决于请求URL.
防爆
@POST("/activate")
public void activate(@Body Request reqdata, Callback callback);
Run Code Online (Sandbox Code Playgroud)
在这里,模拟客户端理解被激活的URL被激活并在assets文件夹中查找名为activate.txt的文件.它从assets/activate.txt文件中读取内容并将其作为API的响应发送.
这是扩展的 MockClient
public class MockClient implements Client {
Context context;
MockClient(Context context) {
this.context = context;
}
@Override
public Response execute(Request request) throws IOException {
Uri uri = Uri.parse(request.getUrl());
Log.d("MOCK SERVER", "fetching uri: " + uri.toString());
String filename = uri.getPath();
filename = filename.substring(filename.lastIndexOf('/') + 1).split("?")[0];
try {
Thread.sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
}
InputStream is = context.getAssets().open(filename.toLowerCase() + ".txt");
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
String responseString = new String(buffer);
return new Response(request.getUrl(), 200, "nothing", Collections.EMPTY_LIST, new TypedByteArray("application/json", responseString.getBytes()));
}
}
Run Code Online (Sandbox Code Playgroud)
有关详细说明,您可以查看我的博客
http://www.cumulations.com/blogs/13/Mock-API-response-in-Retrofit-using-custom-clients
| 归档时间: |
|
| 查看次数: |
54310 次 |
| 最近记录: |