AWS Mobile SDK のテスト手法について発表してきた #AWSSummit
AWS Summit Tokyo 2015 DevCon で発表してきました!
AWS Summit Tokyo 2015 の デベロッパーカンファレンス (DevCon) にて、Dev-06: Mobile セッションで「AWS Mobile SDK 利用時のテスト手法」というタイトルで発表させていただきました。
本記事では、その内容について簡単にご紹介させていただければと思います。
AWS Mobile SDK の活用
よくある構成の課題
モバイルアプリのバックエンドの構成は、EC2 & RDS を使うケースがよくあります。よく使われていて成熟している構成なのですが、モバイルアプリならではといえる課題がいろいろとあります。
- サーバーアプリの開発コストがかかる
- 運用コストがかかる
- トラフィックの増大化に耐えられない
特にトラフィックの増大化が課題で、アプリがヒットする前は問題無かったのに、知名度が上がりユーザー数が増えていくと、徐々にバックエンドが耐えられなくなっていってしまいます。EC2 インスタンス数を増やせば良いのか、RDS の性能を上げれば良いのか、アプリのパフォチューをすれば良いのか、ベストな解決策を見つけ出すのも時間がかかります。
2-Tier アーキテクチャとは?
2-Tier アーキテクチャとはモバイルアプリからバックエンドサービスを直接呼び出す構成を指します。サーバーレス (EC2レス)なのでレイテンシが削減され、運用コストもかかりません。バックエンドサービスの旨味をダイレクトに味わうことができ、インフラをマネージドなサービスに全面的に任せることができます。AWS はこの 2-Tier アーキテクチャを構成するサービスを展開しています。
AWS Mobile SDK を含むスマホアプリをテストするには?
スタブ・モックが必要
スマホアプリでは主にユニットテストと結合テストを行います。結合テストは疎通確認も含まれますが、ユニットテストで AWS サービスの API を直接コールしてしまうとコストがかかってしまいますし、そもそもスマホアプリのテストという意味では不要な場合が多いです。
そこで、AWS Mobile SDK が提供しているサービスクラスのスタブ・モックが必要になります。
スタブ・モックを作るための OSS
iOS・Android のいずれも、クラスをスタブ・モックを作るための OSS が提供されています。
iOS
- OCMock
- OCMockito
- Kiwi
OCMock を使う場合、次のようにスタブ・モックを作成することができます。
AWSSNSCreatePlatformEndpointInput *request = [AWSSNSCreatePlatformEndpointInput new]; request.token = @"token"; AWSSNSCreateEndpointResponse *response = [AWSSNSCreateEndpointResponse new]; response.endpointArn = @"expected_arn"; id stubTask = [BFTask taskWithResult:response]; id stubSNS = OCMClassMock([AWSSNS class]); OCMStub([stubSNS createPlatformEndpoint:request]).andReturn(stubTask);
Android
- Mockito
- EasyMock
- JMockit
Mockito を使う場合、次のようにスタブ・モックを作成することができます。
CreatePlatformEndpointRequest req = new CreatePlatformEndpointRequest().withToken("token"); CreatePlatformEndpointResult exp = new CreatePlatformEndpointResult().withEndpointArn("expected_arn"); AmazonSNSClient stub = mock(AmazonSNSClient.class); when(stub.createPlatformEndpoint(req)).thenReturn(exp);
スタブ・モックを作るときのハマりどころ
AWS SDK for iOS は API をリクエストするためのクラス、それからレスポンスのクラスに isEqual: が実装されていません。そのため、オブジェクト単位でしか等価性が判定できません。
これを解決するためには、クラスを拡張して isEqual: を定義してあげる必要があります。
@implementation AWSSNSCreatePlatformEndpointInput (test) - (BOOL)isEqual:(AWSSNSCreatePlatformEndpointInput*)object { return [self.token isEqualToString:object.token]; } @end
iOS 用 OSS を公開しました!
iOS で AWS Mobile SDK を利用したテストを書くときに、ワンライナーでスタブ・モックを作ることができる OSS 「TAWS」を公開しました。以下のように記述できます。
AWSMock *mock = [[[[AWSMock mockWith:AWSServiceSNS] receive:@selector(createPlatformEndpoint:)] with:request] andReturn:response];
現バージョンは最小限の構成となっていますが、今後機能を増やしていく予定です。ぜひご活用ください。
pod 'TAWS'
まとめ
DevCon は今回の AWS Summit で初めての試みです。AWS Summit では私自身始めての登壇となりますが、このような素敵な場で発表させていただけて光栄でした。今後も AWS x Mobile の活用にチャレンジしていきたいと思います!
余談
pod lib lint は podspec を解析してくれるコマンドです。コマンド引数に何も含めない場合、デフォルトでは警告時もエラーとして扱われます。AWSiOSSDKv2 は以下の様な警告が発生するため、デフォルトのままではエラー扱いになります。
-> TAWS (0.0.1) - WARN | AWSS3/AWSS3/AWSS3TransferManager.h:237:38: warning: auto property synthesis will not synthesize property 'body'; it will be implemented by its superclass, use @dynamic to acknowledge intention [-Wobjc-property-synthesis] - NOTE | AWSS3/AWSS3/AWSS3Model.h:3078:34: note: property declared here - NOTE | AWSS3/AWSS3/AWSS3TransferManager.m:702:17: note: detected while default synthesizing properties in class implementation
そんな時は --allow-warnings を入れましょう。あとついでに --verbose ですべてのログを表示したり --use-libraries で Embedded Framework を使用しないようにする、なども必要になってくると思います。
pod lib lint --verbose --use-libraries --allow-warnings
その他のコマンド引数は以下を参照してください。
pod trunk push するときも同様ですかね。