it-swarm.asia

مربع خادم التحديثية وهمية للاختبار

ما هي أفضل طريقة للسخرية من خادم للاختبار عند استخدام مربع التحديثية التحديثية .

الطرق المحتملة:

  1. إنشاء تحديث جديد عميل وتعيينه في RestAdapter.Builder (). setClient (). يتضمن هذا تحليل كائن الطلب وإرجاع json ككائن استجابة.

  2. قم بتطبيق هذه الواجهة المشروحة كفئة وهمية واستخدمها بدلاً من الإصدار المقدم من RestAdapter.create () (لن تختبر تسلسل gson)

  3. ؟

من الناحية المثالية ، أرغب في أن يكون الخادم المهزوم يوفر استجابات json حتى أتمكن من اختبار تسلسل gson في نفس الوقت.

أي أمثلة سيكون موضع تقدير كبير.

81
Alec Holmes

قررت تجربة الطريقة الأولى على النحو التالي

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()));
    }
}

واستخدامه عن طريق:

RestAdapter.Builder builder = new RestAdapter.Builder();
builder.setClient(new MockClient());

إنه يعمل بشكل جيد ويسمح لك باختبار سلاسل json دون الحاجة إلى الاتصال بالخادم الحقيقي!

78
Alec Holmes

طلبات وهمية التحديثية 2.0 للاختبار

نظرًا لأن الآليات القديمة مثل إنشاء فئة MockClient وتطبيقها من Client لم تعد تعمل مع الإصدار 2.0 من Retrofit ، فإني هنا أصف طريقة جديدة للقيام بذلك. كل ما عليك القيام به الآن هو إضافة أدوات اعتراض مخصصة لـ OkHttpClient كما هو موضح أدناه . فئة FakeInterceptor تتخطى مجرد طريقة intercept وفي الحالة إذا كان التطبيق في وضع DEBUG ، يُعطى JSON.

RestClient.Java

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

IRestService.Java

public interface IRestService {

    String ENDPOINT = "http://www.vavian.com/";

    @GET("/")
    Call<Teacher> getTeacherById(@Query("id") final String id);
}

FakeInterceptor.Java

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

شفرة المصدر للمشروع on GitHub

91
Victor Apoyan

يبدو أن اختبار إلغاء تسلسل JSON لكائناتك (من المفترض باستخدام TypeAdapters؟) يمثل مشكلة منفصلة تتطلب اختبارات وحدة منفصلة.

أنا استخدم الإصدار 2 شخصيا. يوفر رمزًا آمنًا من النوع الآمن وصديقًا لل ريفاكتور يمكن تصحيحه وتعديله بسهولة. بعد كل شيء ، ما هو جيد هو إعلان API الخاص بك كواجهات إذا كنت لا تنشئ إصدارات بديلة منها للاختبار! تعدد الأشكال للفوز.

خيار آخر هو استخدام Java Proxy. هذا هو في الواقع كيفية تطبيق التحديثية (حاليا) تفاعل HTTP الأساسي. سيتطلب ذلك مزيدًا من العمل ، ولكنه سيسمح بتهوية أكثر ديناميكية.

19
Jake Wharton

أنا معجب كبير بـ Apiary.io لسخرية من API قبل الانتقال إلى خادم حقيقي.

يمكنك أيضًا استخدام ملفات .json المسطحة وقراءتها من نظام الملفات.

يمكنك أيضًا استخدام واجهات برمجة التطبيقات التي يمكن الوصول إليها بشكل عام مثل Twitter و Flickr وما إلى ذلك.

فيما يلي بعض الموارد الرائعة الأخرى حول التحديثية.

الشرائح: 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

8
jpotts18

يمكنك أيضًا استخدام شيء مثل Webservermock من Squareup! -> https://github.com/square/okhttp/tree/master/mockwebserver

7
mato
  1. أولاً ، قم بإنشاء واجهة التحديثية الخاصة بك.

    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();
    }
    
  2. الطالب الخاص بك في متابعة:

    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);
        }
    }
    
  3. إذا كنت تستخدم الخيار الثاني (استخدم واجهة Retrofit لبيانات خادم Mock) ، فأنت بحاجة إلى 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();
    }
    

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"
        }
      ]
    }

5. إذا كنت تستخدم okhttp3 interceptor ، فأنت بحاجة إلى interceptor المعرّفة ذاتيًا ، مثل هذا:

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

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!!!
    });
}

شكرا للقراءة.

7
Lai ZuLing

استهزاء (إخلاء المسئولية: أنا المؤلف) تم تصميمه لهذه المهمة بالضبط.

Mockery هي مكتبة ساخرة/اختبار تركز على التحقق من صحة طبقات الشبكات مع دعم مدمج لـ Retrofit. يقوم تلقائيًا بإنشاء اختبارات JUnit بناءً على مواصفات Api. الفكرة ليست أن تكتب يدوياً أي اختبار ؛ لا واجهات تنفيذ للاستهزاء باستجابات الخادم.

6
Víctor Albertos

إضافة إلى الإجابة بواسطةAlec ، قمت بتمديد عميل وهمية للحصول على الاستجابة مباشرة من ملف نصي في مجلد الأصول اعتمادا على عنوان URL الطلب.

Ex

@POST("/activate")
public void activate(@Body Request reqdata, Callback callback);

هنا العميل الوهمي ، يفهم أن عنوان URL الذي يتم تشغيله يتم تنشيطه ويبحث عن ملف يسمى activate.txt في مجلد الأصول. يقرأ المحتوى من ملف الأصول/activate.txt ويرسله استجابةً لواجهة برمجة التطبيقات.

هنا هو الموسعة 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()));
    }
}

للحصول على شرح مفصل يمكنك الخروج مدونتي
http://www.cumulations.com/blogs/13/Mock-API-response-in-Retrofit-using-custom-callents

5
praveena_kd

بالنسبة لي فإن عميل Retrofit المخصص رائع بسبب المرونة. خاصة عند استخدام أي إطار عمل DI ، يمكنك تشغيل/إيقاف تشغيل وهمي بشكل سريع وبسيط. أنا أستخدم عميل مخصص مقدم من Dagger أيضًا في اختبارات الوحدة والتكامل.

تحرير: هنا تجد مثالًا للسخرية من التعديل التحديثي https://github.com/pawelByszewski/retrofitmock

0
Paweł Byszewski