Android
AWS
テスト
DeviceFarm

AWS SDKを使いDeviceFarmでのテストを実行する

More than 1 year has passed since last update.

この投稿の内容に加筆して弊社のブログに投稿しました。

http://tech.vasily.jp/entry/devicefarm_automation


概要

AWS SDKを使用してDeviceFarmへAPKとテストコードをアップロードし、Calabashによるテストを実行してみたのでそのメモです。


APIドキュメントと使用するSDK

ドキュメントは以下を参照しました。

また、SDKにはAWS SDK for Ruby - Version 2を使用します。


AWS SDK Clientの作成

clientを作成します。IAMでAWSDeviceFarmFullAccessのポリシーをアタッチしたユーザを用意し、そのAccessKeyIdとSecretAccessKeyを使用します。また、regionにはus-west-2を指定します。

equire 'aws-sdk'

devicefarm = Aws::DeviceFarm::Client.new(
region: 'us-west-2',
credentials: Aws::Credentials.new("YOUR_ACCESS_KEY_ID", "YOUR_SECRET_ACCESS_KEY"),
)


DeviceFarmのプロジェクト情報を取得

まず試しにDeviceFarmで作成したプロジェクトの情報を取得してみます。プロジェクトを作成していない場合DeviceFarmのコンソールから「Create a new project」をクリックしプロジェクトを作成しておきます。

プロジェクト情報は以下のコードで取得できます。

devicefarm.get_project({

arn: "プロジェクトのARN"
})

ここで、プロジェクトのARNは以下のようになります。

arn:aws:devicefarm:us-west-2:<ポリシーをアタッチしたユーザーID>:project:<DeviceFarmのプロジェクトID>

DeviceFarmのプロジェクトIDは、DeviceFarmでプロジェクトを開いた際のURLの以下の部分を使用します。

https://us-west-2.console.aws.amazon.com/devicefarm/home?region=us-west-2#/projects/この部分/runs


DevicePoolの取得


デバイスプールについて

テストを実行するデバイスの種類は、デバイスプールと呼ばれる単位で管理されています。デバイスプールをAWS SDKから作成することは出来ますが、コンソールから作成した方がわかりやすいです。

コンソールのプロジェクトページに表示される「Create a new run」をクリックすると新しいRun(テスト対象APKやデバイスの種類、テストケースを紐付けたもの)を作成することができますので、一度作成しRunを実行することをおすすめします。AWSのブログ記事が実行まで詳細に書いてあるので参考にしてみてください。


AWS SDKでのDevicePoolの取得

以下のコードでDevicePoolを取得できます。レスポンスにはDevicePoolのARNなどの情報が含まれます。今回はレスポンスに含まれる最初のDevicePoolを使用します。ドキュメントはこちらです。

resp = devicefarm.list_device_pools({

arn: "プロジェクトのARN"
})

# DevicePoolのARN(後ほど使用)
device_pool_arn = resp.device_pools[0].arn


テスト対象APKのアップロード

APKのアップロードは2段階の手順を踏みます。


  • devicefarm.create_upload()でのinitialize

  • Pre-Signed URLを使用したAPKアップロード


initialize

以下のコードで初期化し、Pre-Signed URLを取得します。また、アップロードするオブジェクトのARNを取得しておきます(実行をスケジューリングする際に使用します)。ドキュメントはこちらです。

resp = devicefarm.create_upload({

project_arn: "プロジェクトのARN",
name: "app-debug.apk",
type: "ANDROID_APP",
content_type: "application/octet-stream"
})

# Pre-Signed URLの取得
pre_signed_url = resp.upload.url

# 実行をスケジューリングする際に使用
apk_arn = resp.upload.arn

create_uploadのレスポンスのシンタックスは以下のようになっています。ドキュメントはこちらです。

{

"Upload": {
"Arn": "string",
"ContentType": "string",
"Created": number,
"Message": "string",
"Metadata": "string",
"Name": "string",
"Status": "string",
"Type": "string",
"Url": "string"
}
}

statusは、FAILEDINITIALIZEDPROCESSINGSUCCEEDEDの4種類があり、create_uploadを実行した直後は、INITIALIZEDになり、この状態ではDeviceFarmから利用できません。Pre-Signed URLを利用してAPKをアップロードすることでPROCESSINGとなり、その後SUCCEEDEDへ変化します。ここでPROCESSINGの際に不具合が起きるとFAILEDになります。


upload

こちらを参考に、以下のようなコードでAPKをアップロードできます。

url = URI.parse(pre_signed_url)

apk = File.open("YOUR_APK_PATH", "rb").read
Net::HTTP.start(url.host) do |http|
http.send_request("PUT", url.request_uri, apk, {"content-type" => "application/octet-stream"})
end


テストパッケージのアップロード

今回テストにはCalabashを使用するので、Calabashのfeaturesをzipに圧縮してアップロードします。アップロードの手順はAPKのアップロードと同じです。create_uploadのtypeにCALABASH_TEST_PACKAGEを指定します。

resp = devicefarm.create_upload({

project_arn: "プロジェクトのARN",
name: "features.zip",
type: "CALABASH_TEST_PACKAGE",
content_type: "application/octet-stream"
})

# Pre-Signed URLの取得
pre_signed_url = resp.upload.url

# 実行をスケジューリングする際に使用
calabash_package_arn = resp.upload.arn

url = URI.parse(pre_signed_url)
features = File.open("YOUR_FEATURES_PATH", "rb").read
Net::HTTP.start(url.host) do |http|
http.send_request("PUT", url.request_uri, features, {"content-type" => "application/octet-stream"})
end


テストの実行


実行のスケジューリング

実行のスケジュールは以下のように行います。ドキュメントはこちらです。

app_arnには、APKをアップロードした際に取得したARNを、device_pool_arnはDevicePoolの取得で取得したARNを、test_package_arnにはCalabashのfeatures.zipをアップロードした際に取得したARNを使用します。

devicefarm.schedule_run({

project_arn: "プロジェクトのARN",
app_arn: apk_arn,
device_pool_arn: device_pool_arn,
test: {
type: 'CALABASH',
test_package_arn: calabash_package_arn
}
})


APK、Test packageのアップロード完了を待つ

APK、Test packageをアップロードした直後では、それぞれのstatusがSUCCEEDEDになっているとは限りません。このため、定期的にstatusがSUCCEEDEDかどうか確認する手順が必要になります。

get_uploadを使用すると、uploadしたオブジェクトの状態を取得できるので、それを1秒ごとに取得しstatusを確認します。そして、APK、Test package両方のstatusがSUCCEEDEDならschedule_runを実行します。

10.times do

resp_apk = devicefarm.get_upload({
arn: apk_arn
})

resp_test_package = devicefarm.get_upload({
arn: calabash_package_arn
})

if resp_apk.upload.status == "SUCCEEDED" &&
resp_test_package.upload.status == "SUCCEEDED"

devicefarm.schedule_run({
project_arn: "プロジェクトのARN",
app_arn: apk_arn,
device_pool_arn: device_pool_arn,
test: {
type: 'CALABASH',
test_package_arn: calabash_package_arn
}
})

exit
end

sleep(1)
end

これでスケジューリングされ、DeviceFarm上でCalabashのテストが実行されます。


まとめ

AWS SDKを利用してDeviceFarm上でのテストを実行することができました。今後はCircleCIと連携させGitHubへのPushをトリガーにしてDeviceFarmでのテストを実行できるようにしたいと思います。