Unit Test と Instrumented Unit Test の実行（UnitTest探求記1）

Unit Test 探求記は、unit test に関してまったりと実験しつつその過程を綴ってみるというものです。

# 今回のお題
Unit test と instrumented unit test を実行してみます。

# Unit Test の実行(失敗例)
ここで言う unit test とは、src/test 以下のテストのことを指しています。

わざと間違えて、テストが実行されていることを確認してみます。
[ExampleUnitTest.kt](https://github.com/beyondseeker/chrono0020/blob/e92036e2caccdd3922c26e74028e36ffdecd454e/app/src/test/java/com/objectfanatics/chrono0020/ExampleUnitTest.kt)

```kotlin:ExampleUnitTest.kt抜粋
class ExampleUnitTest {
    @Test
    fun addition_isCorrect() {
        // assertEquals(4, 2 + 2)

        // わざと間違えてみる。
        assertEquals(5, 2 + 2)
    }
}
```
下記のようにコマンドライン上で実行します：

```
$ ./gradlew clean test --info

com.objectfanatics.myapplication.ExampleUnitTest > addition_isCorrect FAILED
    java.lang.AssertionError: expected:<5> but was:<4>
        at org.junit.Assert.fail(Assert.java:88)
        at org.junit.Assert.failNotEquals(Assert.java:834)
        at org.junit.Assert.assertEquals(Assert.java:645)
        at org.junit.Assert.assertEquals(Assert.java:631)
        at com.objectfanatics.myapplication.ExampleUnitTest.addition_isCorrect(ExampleUnitTest.kt:18)
```

ちゃんとテストが失敗していることを確認できました。

# Instrumented Unit Test の実行(失敗例)
ここで言う instrumented unit test とは、src/androidTest 以下のテストのことを指しています。

わざと間違えて、テストが実行されていることを確認してみます。
[ExampleInstrumentedTest.kt](https://github.com/beyondseeker/chrono0020/blob/e92036e2caccdd3922c26e74028e36ffdecd454e/app/src/androidTest/java/com/objectfanatics/chrono0020/ExampleInstrumentedTest.kt)

```kotlin:ExampleInstrumentedTest.kt抜粋
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
    @Test
    fun useAppContext() {
        // Context of the app under test.
        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
        // assertEquals("com.objectfanatics.chrono0020", appContext.packageName)
        fail("I made a mistake on purpose.")
    }
}
```

実機を接続た後、下記のようにコマンドライン上で実行します：

```
$ ./gradlew clean connectedAndroidTest

> Task :app:connectedDebugAndroidTest
Starting 1 tests on ASUS_X00PD - 8.0.0

com.objectfanatics.myapplication.ExampleInstrumentedTest > useAppContext[ASUS_X00PD - 8.0.0] FAILED
        java.lang.AssertionError: I made a mistake on purpose.
        at org.junit.Assert.fail(Assert.java:88)

> Task :app:connectedDebugAndroidTest FAILED
```

ちゃんとテストが失敗していることを確認できました。

# 依存関係を確認してみる
以下に、テスト関連の設定を抜粋し、コメントしてみます。
[app/build.gradle.kts](https://github.com/beyondseeker/chrono0020/blob/e92036e2caccdd3922c26e74028e36ffdecd454e/app/build.gradle.kts)

```kotlin:app/build.gradle.kts抜粋
android {
        // JUnit 4 のテストクラス群を利用するため、AndroidJUnitRunner をデフォルトの test instrumentation runner としてセットしている。
        // instrumented unit test とは実機(やエミュレータ)上で実行される unit test のこと。
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }
}

dependencies {
    // 通常の unit test から利用される JUnit 4 のクラス群への依存。※ org.junit.Test 等
    testImplementation("junit:junit:4.12")

    // instrumented unit test から利用される JUnit 4 のクラス群への依存。※ AndroidJUnit4, ActivityScenarioRule 等
    androidTestImplementation("androidx.test.ext:junit:1.1.1")

    // Espresso testing framework への依存。
    // Espresso testing framework は UI テストのためのフレームワーク。
    // @see https://developer.android.com/training/testing/ui-testing/espresso-testing
    androidTestImplementation("androidx.test.espresso:espresso-core:3.2.0")
}
```

`androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'` を外しても IDE 上で警告は出ませんが、実行時に以下のようになり、instrumented unit test が失敗します：

```
$ ./gradlew clean connectedAndroidTest

> Task :app:connectedDebugAndroidTest
Starting 0 tests on ASUS_X00PD - 8.0.0
Tests on ASUS_X00PD - 8.0.0 failed: Instrumentation run failed due to 'Process crashed.'

com.android.build.gradle.internal.testing.ConnectedDevice > No tests found.[ASUS_X00PD - 8.0.0] FAILED
No tests found. This usually means that your test classes are not in the form that your test runner expects (e.g. don't inherit from TestCase or lack @Test annotations).

> Task :app:connectedDebugAndroidTest FAILED

FAILURE: Build failed with an exception.
```

エラーの表示から依存関係の指定漏れであることを推測するのは難しそうですね、、、。

# Test の実行(成功例)
わざと間違った個所を修正してテストを実行します。

[ExampleUnitTest.kt](https://github.com/beyondseeker/chrono0020/blob/013ee1075230625b8d5a23b12588234246252175/app/src/test/java/com/objectfanatics/chrono0020/ExampleUnitTest.kt)
[ExampleInstrumentedTest.kt](https://github.com/beyondseeker/chrono0020/blob/013ee1075230625b8d5a23b12588234246252175/app/src/androidTest/java/com/objectfanatics/chrono0020/ExampleInstrumentedTest.kt)

```
$ ./gradlew clean test

BUILD SUCCESSFUL in 6s
28 actionable tasks: 28 executed
```
ちゃんとテストが成功していることを確認できました。

# まとめ
今回は、Unit test と instrumented unit test を実行してみました。

# ソースコード
Android Studio により Empty Activity project を生成し、build.gradle を build.gradle.kts に変換したものがベースとなっています。

**▼ テストに失敗するコード**
[source tree](https://github.com/beyondseeker/chrono0020/tree/bb13107f90c9fadac13b8a4d6b7259e222322739)

```:cloneとcheckoutの例
$ git clone git@github.com:beyondseeker/chrono0020.git
$ cd chrono0020
$ git checkout bb13107f90c9fadac13b8a4d6b7259e222322739
```

**▼ テストに成功するコード**
[source tree](https://github.com/beyondseeker/chrono0020/tree/013ee1075230625b8d5a23b12588234246252175)

```:cloneとcheckoutの例
$ git clone git@github.com:beyondseeker/chrono0020.git
$ cd chrono0020
$ git checkout 013ee1075230625b8d5a23b12588234246252175
```