Android Retrofit 單元測試 Unit Test

Model

後端返回的結果都比較統一,通常包含 codemsgdata,建立的 model 使用泛型。java

public class Result<T> {
    private int code;
    private String msg;
    private T data;
    // getter & setter
}
複製代碼

subModel

public class SubModel {
    private long state;
    private long remain;
    private long total;
    // getter & setter
}
複製代碼

Retrofit 網絡庫

官方網站:square.github.io/retrofit/android

配置 app build.gradle

dependencies {
    ...
    implementation 'com.squareup.retrofit2:retrofit:2.6.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.6.0'
    implementation("com.squareup.okhttp3:logging-interceptor:3.14.2")
}
複製代碼

Server

public interface Service {
    @FormUrlEncoded
    @POST("ctrl")
    Call<Result> sendCmd(@Field("cmd") String cmd, @Field("arg") String arg);

    @POST("config")
    Call<Result<Config>> fetchConfig();

    @POST("state")
    Call<Result<State>> fetchState();

    @POST("tfcard")
    Call<Result<TFCard>> fetchTFCard();
}
複製代碼

Injection 注入

public class Injection {

    // 建立 SingleObject 的一個對象
    private static Injection instance = new Injection();

    // 讓構造函數爲 private,這樣該類就不會被實例化
    private Injection(){}

    // 獲取惟一可用的對象
    public static Injection getInstance(){
        return instance;
    }

    private Retrofit provideRetrofit() {
        final String BASE_URL = "http://127.0.0.1:5000/api/";
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .client(provideOkHttpClient())
                .build();
        return retrofit;
    }

    private OkHttpClient provideOkHttpClient() {
        OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
        httpClient.addInterceptor(provideLoggingInterceptor());
        return httpClient.build();
    }

    private HttpLoggingInterceptor provideLoggingInterceptor() {
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        if (BuildConfig.DEBUG) {
            logging.setLevel(HttpLoggingInterceptor.Level.BODY);
        } else {
            logging.setLevel(HttpLoggingInterceptor.Level.NONE);
        }
        return logging;
    }

    public Service provideService() {
        return provideRetrofit().create(Service.class);
    }
}
複製代碼

Unit Test 單元測試

async 異步測試

public void testSomething() {
    final CountDownLatch signal = new CountDownLatch(1);
    Service.doSomething(new Callback() {

        @Override
        public void onResponse() {
            // test response data
            // assertEquals(..
            // assertTrue(..
            // etc
            signal.countDown(); // notify the count down latch
        }

    });
    signal.await(); // wait for callback
}
複製代碼

java.lang.RuntimeException:

java.lang.RuntimeException: Method d in android.util.Log not mocked. See http://g.co/androidstudio/not-mocked for details.
複製代碼

build.gradle 下面 android 項目下添加:git

android {
    ...
   testOptions { 
       unitTests.returnDefaultValues = true
   }
}
複製代碼

添加測試用例github

public class InjectionTest {
    @Test
    public void provideRecoderServiceTFCard() throws Throwable {
        final CountDownLatch signal = new CountDownLatch(1);
        Call<Result<TFCard>> call = Injection.getInstance().provideRecoderService().fetchTFCard();

        call.enqueue(new Callback<Result<TFCard>>() {
            @Override
            public void onResponse(Call<Result<TFCard>> call, Response<Result<TFCard>> response) {
                Result result = response.body();
                TFCard tfCard = (TFCard) result.getData();
                LogUtils.d("tfCard", tfCard.toString());
                signal.countDown();
            }

            @Override
            public void onFailure(Call<Result<TFCard>> call, Throwable t) {
                LogUtils.d("InjectionTest", t.getMessage());
                signal.countDown();
            }
        });

        signal.await(3, TimeUnit.SECONDS);
    }
}
複製代碼
相關文章
相關標籤/搜索