LoginSignup
9
11

More than 5 years have passed since last update.

AndroidのUnitTest用モックサーバーをYAMLとJSONから作る

Posted at

背景

  • ニフティクラウド mobile backendのSDKが4つ
    • iOS / Android / JavaScript / Unity
  • JavaScriptのUnit TestでStubcellを使ったスタブサーバーを用意していた
  • その時のYAMLファイルとJSONファイルを使いまわしてAndroidでもテストしたかった

準備

YAMLを使うライブラリの設定

build.gradleを編集

  • mavenCentralをリポジトリに追加
repositories {
    jcenter()
    mavenCentral()
}
  • dependenciesにsnakeyamlを追加
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.0.0'
    testCompile 'junit:junit:4.12'
    testCompile 'org.robolectric:robolectric:2.4'
    testCompile 'com.squareup.okhttp:mockwebserver:2.3.0'
    compile 'com.google.android.gms:play-services:7.5.0'
    testCompile 'org.yaml:snakeyaml:1.15'
}

Dispatch部分を編集

  • MockWebServerではDispatchを作成してHTTPリクエストのハンドリングが可能
  • Readmeではif / elseでの条件分岐を行っているけど、ようは条件よってMockResponseのreturnができればよい
  • YAMLファイルを読み込んで、引数のrequestと一致するものを探す実装
  • Dispatchを使ったMockWebServerの立て方や、readJsonResponseメソッド(レスポンス用のJSONデータをファイルから読み込むところ)は以下参照
  • YAMLファイルでのリクエスト/レスポンスの書き方もStubcellのReadmeを参照
//URLごとにレスポンスを定義するdispatcherを作成
final Dispatcher dispatcher = new Dispatcher() {

    @Override
    public MockResponse dispatch(RecordedRequest request) throws InterruptedException {
        InputStream input = null;
        try {
            input = new FileInputStream(new File("src/test/assets/yaml/test.yml"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        //YAMLオブジェクトを作成
        Yaml yaml = new Yaml();

        Map<String, Object>map = null;
        Map<String, Object>requestMap = null;
        Map<String, Object>responseMap = null;

        //YAMLファイルから---で区切られたデータを取得
        for (Object data : yaml.loadAll(input)) {
            map = (Map<String, Object>)data;
            requestMap = (Map)map.get("request");
            responseMap = (Map)map.get("response");
            if (requestMap.get("url").equals(request.getPath())){
                if (requestMap.get("method").equals(request.getMethod())){
                    //Responseを返す
                    return new MockResponse().setResponseCode((int)responseMap.get("status"))
                                             .setHeader("Content-Type", "application/json")
                                             .setBody(readJsonResponse(responseMap.get("file").toString()));
                }
            }
        }

        //デフォルトのレスポンスを設定
        return new MockResponse().setResponseCode(404)
                                 .setHeader("Content-Type", "application/json")
                                 .setBody(readJsonResponse("valid_error_response.json"));

    }
};
  • YAMLファイルサンプル
---
  request:
    url: /2013-09-01/classes/TestClass
    method: POST
  response:
    status: 201
    file: valid_post_response.json
---
  request:
    url: /2013-09-01/classes/TestClass/7FrmPTBKSNtVjajm
    method: PUT
  response:
    status: 200
    file: valid_put_response.json
---
  request:
    url: /2013-09-01/classes/TestClass/7FrmPTBKSNtVjajm
    method: GET
  response:
    status: 200
    file: valid_get_response.json
---
  request:
    url: /2013-09-01/classes/TestClass/7FrmPTBKSNtVjajm
    method: DELETE
  response:
    status: 200
    file: valid_delete_response.json

さいごに

  • (まだ)urlとメソッドでしかハンドリングに対応していません
    • request bodyとかquer stringとか。。。
  • (まだ)url parserには対応してません(placeholder /user/:userId みたいなやつ)
  • iOSでも同じことをやれば、YAMLとJSONファイルがある意味テストの仕様書になる
  • テストコードもすっきりするはず
9
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
11