APP開發實戰176-伺服器介面的單元測試

xjbclz發表於2017-05-30

31.19 伺服器介面的單元測試

在APP開發中,往往介面開發和APP開發的進度是並行的,甚至還落後於APP開發,導致在APP端除錯介面非常麻煩,如果在APP端能模擬介面呼叫,那就極大的提高了APP開發和測試的效率。

31.19.1 單元測試簡介

用Android Studio新建工程後,在app的java資料夾中,通常會包含如下三個資料夾:一個是app實際執行使用的程式碼資料夾,另兩個就是單元測試程式碼的資料夾。如下圖所示:

這兩個單元測試資料夾:一個是供androidTest用的,這類單元測試程式碼只能在Android裝置或模擬器上進行;一個是供test用的,這類單元測試程式碼可以直接在電腦上執行,不需要連線模擬器和Android裝置。

想要執行單元測試程式碼,則滑鼠選中ApplicationTest或ExampleUnitTest檔案,點選滑鼠左鍵,在可以看到Run ‘ApplicationTest’或Run ‘ExampleUnitTest’的選單,點選就可以執行androidTest或test單元測試的程式碼了。

31.19.2 使用MockWebServer進行介面的單元測試

    Square提供了一個能夠模擬介面呼叫的工具MockWebServer,可以很方便的整合在APP中,進行介面相關功能的測試。

    下面就以使用的比較多的volley+okhttp 這種網路庫的組合方式為例,說明MockWebServer的使用。

    首先需要在工程中整合MockWebServer庫檔案。

    AndroidStudio預設有兩種單元測試:androidTest和test,那麼在gradle中整合單元測試的庫,也有兩種方式:

//供androidTest用

androidTestCompile 'com.squareup.okhttp3:mockwebserver:3.6.0'

//供test用

testCompile 'com.squareup.okhttp3:mockwebserver:3.6.0'

    mockwebserver庫的版本號最好與okhttp庫的版本號一致,否則可能會編譯出錯。

    如果APP和伺服器互動使用的是json格式的資料,那執行test單元測試程式碼時,還需在工程中整合json.jar檔案:

testCompile files('libs/json.jar')

    否則會執行出錯。

    如果執行AndroidTest單元測試程式碼,則不需要整合json.jar檔案。

 

模擬呼叫登入介面的具體程式碼如下:

public class ApplicationTest extends ApplicationTestCase<Application>{

    final String TAG = "ApplicationTest";

    //定義介面返回的Json字串
    String strJson = "{\"status\":\"success\"}";

    final BlockingQueue<Object> queue= new ArrayBlockingQueue<>(2);

    //建立MockWebServer物件
    MockWebServer server = new MockWebServer();

    public ApplicationTest() {
        super(Application.class);
    }

    @Test
    public void testLogin() throws Exception{
       

        // 設定介面返回的狀態碼、頭欄位的內容和Body體的內容
        MockResponse response = new MockResponse()
                .setResponseCode(200)
                .addHeader("Content-Type","application/json;charset=UTF-8")
                .setBody(strJson);

    //利用throttleBody函式可以模擬弱網狀態,當前設定每秒傳輸512個位元組的資料
        response.throttleBody(512, 1,TimeUnit.SECONDS);

        server.enqueue(response);

        // 啟動server
        server.start();

        login("admin", "123456");
    }

    public void login(String userName,String password){

        JSONObject jsonObject = new JSONObject();

        try {
            jsonObject.put("jsonrpc","2.0");
            jsonObject.put("method","call");
        } catch (JSONException e) {
            e.printStackTrace();
        }

        JSONObject params = new JSONObject();

        try {
            params.put("app_version","0.6.0");
            params.put("login",userName);
            params.put("password",password);

            jsonObject.put("params",params);
        } catch (JSONException e) {
            e.printStackTrace();
        }

        try {

           //獲取請求URL,不能使用普通的URL,一定要使用server.url()返回的 URL,不然沒法連線Mock伺服器
            String pathUrl = server.url(Urls.LOGIN).toString();
            Log.v(TAG, "url: " +pathUrl);

            request(pathUrl, jsonObject,UserInfo.class);
        }catch (Exception e) {
            e.printStackTrace();
        }

    }

    private void request(String url,JSONObject jsonObject, final Class<?> type) throws Exception {
        NetworkManager.getInstance(EamApplication.getContext()).JsonRequest(TAG,url, jsonObject,
                new Response.Listener<JSONObject>(){
                    @Override
                    public void onResponse(JSONObjectjsonObject) {

                    Log.v(TAG, "responsejson物件: " +jsonObject.toString());

                   //volley庫用到非同步的回撥,在此使用BlockingQueue來等待伺服器的返回結果,然後驗證結果

                    queue.add(jsonObject.toString());

                    parseToResponse(jsonObject,type);

                    }
                }, new Response.ErrorListener(){
                    @Override
                    public void onErrorResponse(VolleyErrorerror) {
                        Log.e(TAG,error.getMessage(), error);
                    }
                });

        //獲取傳送的請求資料
        RecordedRequest request = server.takeRequest();

        assertEquals("POST",request.getMethod());

        Log.v(TAG, "path: " +request.getPath());

        Log.v(TAG, "body: " +request.getBody().toString());

       //驗證伺服器的返回結果是否和預期結果一致
        Object obj = queue.take();
        if (obj instanceof String) {

            Log.v(TAG, "queue json物件: " + obj.toString());

            assertEquals(strJson,obj.toString());
        }

        //關閉server
        server.shutdown();
    }
}

相關文章