Android
test
スクリーンショット
UIテスト
Spoon

Spoonで実現する、UIテストのスクリーンショット事始め

皆さん、UIテスト書いていますか?

ユニットテストなら何とかという人でも、UIテストとなるとUIの更新頻度や費用対効果的な側面から、きっちりやっているというのは少ないのではないでしょうか。

そんな折、下記の素晴らしい記事を拝見し、スクリーンショットを撮るだけでもかなり効果があるのではないかと感じました。

AndroidアプリのゆるいUIテストをSpoonで実現する
https://qiita.com/oxsoft/items/d5774cc9c6016c3c28ec

で、いざSpoonでスクリーンショットを撮るところまでやってみようとしたものの、見事に躓いてしまったので、一旦 UIテストのスクリーンショットを撮る までを実現するところまでを記事にしたいと思います。

※ Spoon
https://github.com/square/spoon

Gradle Spoon Pluginを使用する

GitHubのページからjarをダウンロードしてゴニョゴニョする、ということも出来るようですが、楽をするためにGradleのプラグインを使用します。

(1). https://github.com/stanfy/spoon-gradle-plugin
(2). https://github.com/jaredsburrows/gradle-spoon-plugin

2つほどあるようですが、(1)に関しては最終更新日が1年以上前のようで、Android Gradle Pluginもver. 2までとのことで(2)のほうを使うことにしました。

導入

基本的にはREADMEに書いてあるものをコピペで問題ありませんでした。

build.gradle
buildscript {
  repositories {
    google()
    jcenter()
    maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
  }

  dependencies {
    classpath "com.jaredsburrows:gradle-spoon-plugin:1.4.0"
  }
}
app/build.gradle
repositories {
  maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
}

apply plugin: "com.android.application"
apply plugin: "com.jaredsburrows.spoon"

dependencies {
  androidTestCompile "com.squareup.spoon:spoon-client:2.0.0-SNAPSHOT"
}

テストクラスを作成

サンプルとして MainActivity をテストするクラスを作成します。
スクリーンショットを撮る必要などがあるため、 androidTest のディレクトリに作成することになります。

下記コードは、MainActivityを起動してスクリーンショットを撮る、というコードになります。

app/src/androidTest/java/test/spoon/MainActivityTest.kt
import android.content.Intent
import android.support.test.rule.ActivityTestRule
import android.support.test.runner.AndroidJUnit4
import com.squareup.spoon.SpoonRule
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class MainActivityTest {
    @Rule
    @JvmField
    val activityRule = ActivityTestRule(MainActivity::class.java, false, false)

    @Rule
    @JvmField
    val spoon = SpoonRule()

    @Test
    fun screenshotMainActivity() {
        val mainActivity = activityRule.launchActivity(Intent())
        spoon.screenshot(mainActivity, "MainActivity")
    }
}

ポイント
Spoon ver.2 からなのかわかりませんが、GitHubのサンプルコードでは Spoon.screenshot というメソッドでスクリーンショットを撮れるようですが、それが出来ず、代わりに @Rule アノテーションを用いて SpoonRule というクラスを使うことでスクリーンショットを撮ることが出来るようでした。

パーミッションを追加

これでOKと思い ./gradlew spoon を実行すると下記のようなエラーが発生しました。

> Task :app:spoonDebugAndroidTest
2018-04-12 20:52:39 [SR.runTests] Executing instrumentation suite on 1 device(s).
2018-04-12 20:52:44 [SDR.handleFiles] Found class name dirs: []


FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:spoonDebugAndroidTest'.
> Tests failed! See /Users/user_name/Spoon/app/build/spoon-output/debug/index.html

Spoonでは、テストの結果がHTMLとなって生成されるのでそれを見てみます。
a60de35a983802c51c9acbd2b0b31e4c.png

ディレクトリを作れないエラーのようです。

ポイント
Spoonではスクリーンショットを保存したりする関係上、外部ストレージへのパーミッションが必要となります。 (WRITE_EXTERNAL_STORAGE

そのままパーミッションを追加してもいいですが、アプリとして WRITE_EXTERNAL_STORAGE が不要な場合は、debug用のAndroidManifest.xmlを作り、そちらだけに定義するのもいいかもしれません。

debug/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="test.spoon">

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

</manifest>

これで準備は完了で、 ./gradlew spoon でスクリーンショットが保存されるようになります🚀 (※ Runtime Permission用の設定をしてないのにWRITE_EXTERNAL_STORAGEが使えているのはよくわかりません。)

9f889bf1e83cdfb4768acac454173a3c.png

app/build/spoon-output というフォルダにスクリーンショットの画像などが生成されています。

82624340f0159803874478cd5e89c4ab.png

まとめ

Spoonを用い、UIテストのスクリーンショットを撮るところまで説明しました。躓いた点はあるものの、意外とすんなりと導入することが出来たかと思います。

きっちりしたUIテストを書くのはしんどいかもしれませんが、ゆるいUIテストとしてスクリーンショットを撮っていくのはなんとかやっていけそうな感があったので、機会があれば実践していきたいところです。

ちなみにスクリーンショットを撮って、差分をチェックとかをするのがいいと思いますが、冒頭に紹介した投稿でも言及されているように、スクリーンショットにタイムスタンプが入っていたり、運用していくためにはもう少しカスタマイズしていく必要がありそうです。