Junit5(spek)+mockk+jacoco+bitriseを始めるのは簡単だったよという話(割と新人向け)


まえふり

ども、八流エンジニアです。
早速ですが、昨今の開発現場の実態として、テストを書いてないプロダクトも世にはありますし、
テストは書いてあるけれども、さまざまな理由でメンテナンスされておらず、
今は動かされていない・・なんてことがあります。

僕個人としてはテスト作るのめんどくさいのでテスターにぶん投げたいという本音がありますが、
テストコードは書けた方が得なので、若い人々は書けるようになりましょう。
(テストコード書く利点は、運用保守以外にも設計などにも関わってくるんですが、その話は誰かに聞いてください)w

目的

  • テストクラスが気軽に作れるというのを伝える
  • テスト実行もCIにやらせれば楽というのを伝える
  • 自分の技術的関心のある、CodeCovを拝んでみたい

前提

  • bitriseはアカウント作成を事前にしてください。
  • codeDevはアカウント作成を事前にしてください。
  • spekはライブラリだけでなく、即実行するためにIDE上にプラグイン(Spek Framework)を入れてください。
  • 迷ったら参考資料みてやっているんで、参考資料をみてください 草

やったこと

  • 週末にテストクラス作る
  • 対象は、以前土日に作ったサンプルアプリに実装する
  • ついでにbitriseとjacocoにも手を出す

結果

成果物

試行錯誤して失敗しまくりましたが、どうにかなりましたw

ログも載せようと思ったのですが、あまりに長いので、割愛します。
やったことは、標準のworkFlowに、Scriptと、CodeCovを追加しただけです。

作成したテストクラスを元に、テストクラスの見やすさをアピール

今までテストクラスを見たことも、書いたことない人には、大変伝わりにくいけど・・・
とにかく、可読性が上がって見通しやすくなったし、スマートに書けるようになりました。

以下のコード見てもらって、それがなんとなく伝わればいいなと思う。

class MainViewModelTest : Spek({

    // SpekによりboforeEachとか、いらない。アノテーションもいらなくなった!
    val usecase by memoized {
        mockk<TopAction>()
    }

    val viewModel by memoized {
        MainViewModel(usecase, mockk())
    }

    describe("MainViewModel#request") {
        context("normal pattern") {
            it("success") {
                // coEveryは、suspendに使う
                coEvery {
                    usecase.invoke(mockk(), mockk())
                } returns Unit // 戻りなしはUnitで済ませる
                //実際テストすること
                viewModel.request()
                //想定結果
                coVerify {
                    usecase.invoke(mockk(), mockk())
                }
            }
        }
    }
})

すごいざっくりまとめる

spekの機能で、説明書いています。
describe,contest,it
「このテストはなんのための、どういう意図のテストなのか」みたいな感じです。

テスト内容と実際の確認はmockkが担っています。
モック(mockk)したものを、検査(coVerify)しているだけです。

このテスト内容で確認したかったことは、
viewModel.request()を実行するとusecase.invoke(mockk(), mockk())が、
実行されることを確認したい。
というシンプルなことです。
実際usecase#invokeは呼ばれているため、想定通り、ということになりました。(テストクリア)

テストクラス開発中はいいけど、
いざ動かしていると、1つずつテストクラス実行するのも面倒臭いので、CI(Bitrise)に任せる。
というのをしました。
bitriseは難しいことなく、基本ポチポチするだけで終わるので、あまり言いたいことないですね。

他の方の記事通りやって、
割とスムーズに環境用意できたし、テストも実施できたし、
テストもかなり可読性のいいものになったと思います。

何が言いたかったかというと、
サンプルアプリを作れるレベルの方なら、テストクラスも作れると思いますよ。
テストクラス作れるなら、簡単なCI/CD導入くらいならできると思いますよ。
という事です。

ここで記事終わってもいいんですが、まだできそうな事とかが残っているので、以下にメモ残します。

ハマったこと

  • jacocoの設定が動かない
    • 記事の手順書に従っても、うまくいかない
    • バージョンや環境が完全一致なため仕方ない
    • ログ見て地味に潰していく
packagingOptions {}を追加したり、logにそって修正を入れる

実はまだハマっているw

  • CodeCov連携ができていない。
    • テスト結果がうまく反映されていない模様
    • junit5との相性が悪い?issueが上がっていたがどうなったんだろう・・
    • 今回得たかった、bitriseからCodeCov呼び出すはできたから良しとする

拡張できそうだけどやってないこと

  • fastlaneの導入
    • ストアリリースまで想定するなら、androidでもfastlaneは使えるみたい
    • ただ、ストアリリースがないなら、無理に使う必要なさそう

参考資料

@sadashi を信じろ(敬称略)

memorizedが笑えるくらいスマートにかける

拡張関数で対応するといい kotlinx-coroutines-test