🌸

ユニットテスト導入しました

2024/04/04に公開

こんにちは、Androidチームの田村です。

今回 kotlin で開発されているプロジェクトに junitmockk によるユニットテストを導入した話をしたいと思います。

導入経緯

弊社Androidチームは今まで実機を動かして目視による人力のテストのみを行っていました。弊社村川のマルチモジュール化の記事でも紹介したように、リアーキテクチャを進めていく上で品質担保の自動化も並行して行っていこうとユニットテスト導入の流れとなりました。

今までは各モジュールが密結合した状態で、ユニットテストを導入しようにも出来ない状態となっていましたが、アーキテクチャを根幹から見直し、レイヤーを分けて各モジュールの依存性を下げるようコードをリファクタリングしていった結果、ユニットテストを徐々に導入することができる様になりました。

テスト導入

テストライブラリは一般に使用されているjunitとkotlin用のモックライブラリmockkを導入しました。

テスト対象として、リアーキテクチャによりレイヤー構造をAPI層、データ層、ユースケース層、UI層に分けており、テスト対象はユースケース層とUI層のみとしました。

またユニットテストが初めてのチームメンバーもいるということで、まずは以下のような項目に絞って書き始めることとしました。

  • 入力した値と出力される値が期待通りに変換されるか
  • 日付の範囲チェックが正確におこなわれているか(境界値テスト)

実際のユニットテストのコードの一例

class HomeUseCaseTest {

    // テスト名称は何のテストをやっているかが後から見ても分かりやすい様にあえて日本語名
    @Test
    fun `ログインユーザー更新時の更新フラグがたつかの確認`() {
        val appApiRepository = mockk<AppApiRepository>()
        val loginUserRepository = mockk<LoginUserRepository>()
        val homeUseCase = HomeUseCase(
            appApiRepository = appApiRepository,
            loginUserRepository = loginUserRepository,
        )

        // 更新後のログインユーザーの情報をAPIから取得する中断関数をcoEveryでモック
        coEvery { loginUserRepository.getLoginUser() } returns LoginUserInfoGetResponse(
            user = LoginUserResource(
                id = 1,
                name = "田中 太郎",
                skill = listOf(
                          skill_id = 1,
                          label = "弱電",
                ),
            ),
        )

        runTest {
            val actual = homeUseCase.isUpdated(
                // 更新前のログインユーザーの情報
                loginUser = LoginUser.Individual(
                    id = UserId(1),
                        name = "田中 太郎",
                        skill = listOf(
                                  skill_id = 2,
                                  label = "強電",
                        ),
                ),
            )
            val expected = true

            // 更新されていることを確認
            assertThat(actual).isEqualTo(expected)
        }
    }
}

Github Actionsによるテスト自動化

今回ユニットテスト導入と並行して、プロジェクト内のユニットテストが全て合格するかを自動で検知できるようGithub Actionsによる自動化もしてみました!

以下がそのワークフローになります。

name: Android Unit Test

on:
  pull_request:
    branches: [ "main" ]

jobs:
  unit_test:
    runs-on: ubuntu-latest

    steps:
      # ブランチのチェックアウト
      - name: Checkout
        uses: actions/checkout@v4

      # JDKのセットアップ
      - name: Set up JDK
        uses: actions/setup-java@v4
        with:
          distribution: 'temurin'
          java-version: ${{ secrets.JAVA_VERSION }}
          cache: 'gradle'

      # テストの実行
      - name: Run unit test task
        run: ./gradlew testDevelopDebugUnitTest

これにより全てのユニットテストを自動で行なってくれるので作業者による実行漏れを抑制でき品質を担保できます。

不合格となって機能していることを確認できた時は、リアーキテクチャを経てCIも整備できやっとここまできたかと感慨深い気持ちになりました!

Github Actions

導入してみて

テストを記述している途中で結果が不合格となり早期に不具合の発見・修正ができ、機能改修を行った際に他の機能に影響を与えていないかも自動で検知出来るためデグレの抑制による品質の担保が可能となりました!特に後者は初めて自分が触る機能でもすでに担保されたテストがあると安心感を持って開発できるので開発生産性の向上にも繋がっています。

今後はJaCoCoなどのコードカバレッジ計測ツールの導入とGithub Actionsを利用したレポートの自動出力を整備し、ユニットテストが網羅できていない箇所の洗い出しやテストパターンの増強をしていき、より迅速かつ堅牢な開発を行える環境を構築していきたいと思っています!

さいごに

助太刀では一緒に開発してくれるメンバを募集してます!
少しでもご興味を持っていただけたら下記よりお気軽にご連絡ください!

助太刀テックブログ

Discussion