Wondershake 開発者ブログ

LOCARI(ロカリ)の運営会社の開発者ブログです。

Androidアプリのテスト自動化

WondershakeでLocariのAndroidアプリを開発している代蔵です.

今回は,私が担当しているAndroidアプリのCIについてご紹介しようと思います. Androidアプリの開発者が私一人ということもあり,テストなどを出来るだけ自動化することで開発に専念できるような環境を作りました.

大まかな流れ

  1. GithubへPush (marge)
  2. PushをトリガーにCircleCIでUnitテスト,UIテスト
  3. Slackに結果を通知
  4. Fabricで開発チーム(release)・社内全体(master)にAPKを配布
  5. AWS Device Farmでモンキーテスト(master)

f:id:takumiumiu:20160623175741p:plain

1 GithubへPush(marge)

書いたコードをGitHubへPush.または,release, masterブランチへのPRのmerge.

2 PushをトリガーにCircleCIでUnitテスト,UIテスト

以下はcircle.ymlの一部抜粋になりますが,CircleCI上でUnitテストとUIテストを行っています. UnitテストはJUnit,UIテストはSpoonを使っています. Spoonを使っている主な理由は,画面のスクリーンショットを記録することでUIに問題ないかどうかを目視で確認できるようにするためです.

test:
  pre:
    # create sdcard
     - mksdcard -l e 512M mysdcard.img

    # start emulator
     - emulator -avd circleci-android22 -no-audio -no-window -sdcard mysdcard.img:
         background: true
         parallel: true

    # wait for booted
     - circle-android wait-for-boot

    # avoid com.android.builder.testing.api.DeviceException: com.android.ddmlib.ShellCommandUnresponsiveException
     - sleep 10

  override:
     - ./gradlew testDebug

     - ./gradlew spoonDebugAndroidTest:
         timeout: 1800

     - cp -r /home/ubuntu/locari_android/app/build/outputs/apk/* $CIRCLE_ARTIFACTS
     - cp -r /home/ubuntu/locari_android/app/build/spoon-output/* $CIRCLE_ARTIFACTS

3 Slackに結果を通知

CircleCIの結果をSlackに通知しています.

4 Fabricで開発チーム(release)・社内全体(master)に配布

releaseブランチでテストが全て通った場合は開発チームに,masterブランチでテストが全て通った場合は社内全体へFabric経由でAPKが配布されます. その他のブランチでは,配布されないようになっています.

5 AWS Device Farmでモンキーテスト(master)

最後に,masterブランチですべてのテストが通った場合にのみ,AWS Device Farmでテストを行うようになっています. これにより,Android版Locariでは最低限の品質を担保しています.

アプリのリリース

CircleCI上のUIテストで取得したスクリーンショットAWS Device Farmで問題が無いかどうかを確認. 全てに問題がなかった場合にのみCircleCIからAPKをダウンロードし,Google Playでリリースするという流れになっています. f:id:takumiumiu:20160623180604p:plain

最後に

細かい部分などは省略していますが,弊社のリリースまでの全体像を把握することが出来るかと思います. アプリのリリース作業などはまだ自動化していませんが,今のところ自動化の必要性は感じていません.

最近CircleCI上でOutOfMemoryErrorが多発していて,複数端末でのUIテストが出来ていないので,CircleCIから別のものに移行しようと検討中です.

弊社ではAndroidiOS,サーバサイドエンジニアを募集しています.ご興味の有る方がいれば是非こちらからご応募下さい!

www.wantedly.com

WWDC16 キーノート発表内容のまとめ

こんにちは、iOSエンジニアの藤井です。

現地時間13日の朝に行われたばかりのWWDC 16のキーノートで発表された内容のうち、注目すべき点を速報っぽく簡単にまとめました。

watchOS

watchOSは3が発表されました。

  • アプリの起動速度が爆速の7倍に。メモリとバックグラウンド更新を活用して実現。
  • アプリにすぐにアクセスできるドック機能も追加。
  • 手書き入力の強化。アルファベットだけでなく漢字(中国語)にも対応してます。
  • SOS発信機能。長押しすることで自動的に警察や登録しておいた家族などに自身の位置などを送信。
  • その他エクササイズ系の機能充実。

と3になってやっとそれらしい機能が充実してきたかなという印象。

tvOS

Apple TVに入っているtvOSは主にSiriの進化。文章での音声検索が相当優秀になったとのこと。 他には、シングルサインオン機能で、iOS側でログインしていればApple TVでも自動でログインされ、ID/Passwordの入力が不要になります。

macOS

OS Xは噂通りmac OSへ改名。ここ数年のカルフォルニアに関する固有名詞を付けるルールは引き継がれ、Sierraとなりました。 元ネタはシエラネバダ山脈のことかな。

主な追加機能としては

  • Siri Mac版がついに登場。ファイル検索をしてくれるなどよりアシスタントっぽくなりました。
  • オートアンロック機能。Apple Watchで画面ロックを解除できるようになりました。
  • クリップボード共有機能。Macでコピーした文章などをiPhoneで貼り付けできるように。またその逆もしかり。
  • iCloud経由でファイル間共有の強化。
  • Macのハードディスクが一杯になった時に不要なファイルを自動で整理して空き容量を増やす便利機能もしれっと追加。
  • Apple Payでの支払い。ブラウザ上でApple Payボタンを利用する際に手元のiPhoneで認証すればそのまま支払いできる。

辺り。

iOS

iOSはついに10へ! ということで10の機能更新が行われました。

  1. Notificationやコントロール機能の充実。3D Touchで更に情報を引き出せるようになったり、返信周りがかなり拡充されたのでもはやアプリを開かなくても用が済むように。

  2. Siriのサードパーティへの開放。Siriがサードパーティのアプリと一部連携できるようになり、WeChatのメッセージに返信したり、Uberを呼んだりできるようになりました。

  3. キーボードがよりインテリジェンスに。Deep Learningによる予測変換で会話の流れを読んで変換候補を出してくるようになりました。単純にテキストの候補だけでなく現在位置や電話帳、スケジュールなどを候補に出したり登録したりといったことができるようになります。ちゃんとワークすればかなり便利そうな予感。

  4. 写真アプリも更新。顔や場所などを認識して自動でカテゴリ分け、ロードムービーまで生成してくれるようになりました。Googleフォトやショートムービー作成系アプリを一気に倒しにきてる感。

  5. 地図アプリもスケジュールなどから行く場所を予測して表示などができるように。ナビもちょっと優秀になりました。

  6. ミュージックアプリはデザインの一新。一応使いやすくなったとのこと。

  7. Newsアプリも同じくデザインの一新。ミュージックアプリ同様Boldのフォントを使ったデザインを押し出していく様子。

  8. 日本だといまいち馴染みの薄いHome KitはHomeアプリとして登場。手元のアプリひとつで家のもの全てが操作できるように(したい)。

  9. 電話も更新。留守番電話のメッセージの書き起こし(beta)やサードパーティーで提供されている電話機能と繋げて電話できるように。

  10. メッセージアプリは大幅アップデートで、サードパーティーで提供されているようなおもしろ機能を一通り追加。そしてメッセージストアを用意して開発者へ開放、スタンプなど拡張機能を自由に追加できるように。

Swift

Swift関連ではSwift playgroundsというiPadアプリが登場。小学生くらいの子どもたちが楽しくSwiftやプログラミングを学べる仕組みが用意されているようです。子ども向けながら、大人の初学者でも利用できそうなくらいの作り込み。

まとめると

watchOS, tvOS, macOS, iOSという4種類のOSとそれが入ったデバイス間でのスムーズな連携の強化が今回のテーマの一つのように感じられました。前バージョン辺りからその傾向はありましたが、今回もオートアンロック機能やクリップボード共有、Apple Payでの支払いなど、今まで欲しかった連携機能が欲しい形で追加されています。どれか一つのOSやデバイスに集約するのではなく、それぞれに役割を与えて連携させていくという考えた方は個人的に好感が持てます。 他では、Siriとそれに付随するDeep Learning機能の追加、今まで開発者へ開放されていなかったAPIの部分開放辺りが注目すべき点でしょうか。

4つの新しいOSの開発者プレビュー版は本日から利用開始とのことで、早速触ってみようと思います!

SQLだけで勤怠データから曜日ごと、日中・深夜勤務時間を算出する(Postgres編)

こんにちは。千葉です。

開発者ブログをはじめよう、ということで初ポストです。

弊社には勤怠管理用の社内システムがあり(ちょうどいい勤怠システムってあんまりないですよね...!)そのメンテナンスもしています。

そこで今回「曜日や日中・深夜の勤務時間によって時間数を分けて表示してほしい」という案件が降ってきました。 素直にRuby on Railsで実装したり、適切な設計がしてあれば簡単な実装ですが、諸事情によりSQL(Postgres)だけで表示したい!ということになりました...!厄介ですね。

どうしよう、どうしようと先延ばしにしているうちに同じく開発部のエリックが考えてくれました。 方針としてはこうです。

  • 曜日は EXTRACT(DOW FROM date) すれば簡単に出せるのでそれで判定
  • 時間は LEASTGREATEST を駆使して境目の時間ごとに判定

Locariでは普段MySQLを使っているので、Postgresの勉強になりました。

この方針にのっとって、下記のテーブルがあるとすると、 (実際のテーブルのカラムをいくつか省いています)

                                            Table "public.user_attendances"
          Column          |            Type             |                           Modifiers
--------------------------+-----------------------------+---------------------------------------------------------------
 id                       | integer                     | not null default nextval('user_attendances_id_seq'::regclass)
 status                   | integer                     | not null default 0
 user_id                  | integer                     | not null
 is_at_office             | boolean                     | not null default true
 date                     | date                        | not null
 started_at               | timestamp without time zone |
 ended_at                 | timestamp without time zone |

平日の日中の勤務時間を出すクエリーは下記のようになります。

  • 実際には休憩時間も引く必要があるのでもうちょっと複雑になります
  • DBにはUTCで保存されているので、9時間足しています。
SELECT
  "User Attendances"."user_id" AS "Id",
  EXTRACT(EPOCH
          FROM
          CASE WHEN EXTRACT(DOW FROM date) <> 0
            THEN
              GREATEST(
                  INTERVAL '0',
                  LEAST(
                      (started_at + INTERVAL '9 hours') :: DATE + INTERVAL '22 hours',
                      ended_at + INTERVAL '9 hours'
                  ) - GREATEST(
                      (started_at + INTERVAL '9 hours') :: DATE + INTERVAL '5 hours',
                      started_at + INTERVAL '9 hours'
                  )
              )
          ELSE INTERVAL '0'
          END
          +
          CASE WHEN EXTRACT(DOW FROM date + INTERVAL '1 days') <> 0 AND
                    ((started_at + INTERVAL '9 hours') :: DATE < (ended_at + INTERVAL '9 hours') :: DATE)
            THEN
              GREATEST(
                  INTERVAL '0',
                  LEAST(
                      (ended_at + INTERVAL '9 hours') :: DATE + INTERVAL '22 hours',
                      ended_at + INTERVAL '9 hours'
                  ) - (
                    (ended_at + INTERVAL '9 hours') :: DATE + INTERVAL '5 hours'
                  )
              )
          ELSE INTERVAL '0'
          END
  ) / 60                       AS "月~土通常時間"
FROM "public"."user_attendances" AS "User Attendances"
WHERE ("User Attendances"."date" BETWEEN {CALENDAR.START} AND {CALENDAR.END}
AND ("User Attendances"."status" = 1))

すごいですね...!久しぶりにこんなクエリーを書きました。 でもおかげで、正しい時間数が算出できるようになりました。

WondershakeではSQLを駆使してLocariや会社をよくしてくれる人を探しています! よかったらご応募ください!