背景
- ニフティクラウド mobile backendのSDKが4つ
- iOS / Android / JavaScript / Unity
- JavaScriptのUnit TestでStubcellを使ったスタブサーバーを用意していた
- その時のYAMLファイルとJSONファイルを使いまわしてAndroidでもテストしたかった
準備
- AndroidのUnit Test環境の構築は以下を参照
- MockWebServerを使ってAndroidアプリのHTTP通信テストをしてみる
- assetsフォルダにあるレスポンスのJSONファイルを読み込むところまではできていた
YAMLを使うライブラリの設定
- snakeyamlを使う
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データをファイルから読み込むところ)は以下参照
- MockWebServerを使ってAndroidアプリのHTTP通信テストをしてみる
- 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ファイルがある意味テストの仕様書になる
- テストコードもすっきりするはず