[書評] テストが書けない人のAndroid MVP

テストが書けない人のAndroid MVP」という本がとても良かったので紹介します。MVPでAndroidアプリ開発をしているものの、「テストをどうやって書けばいいのか、よくわからないな…」と思っていたのですが、この本はそんな私にピッタリの本でした。これでMVPのテストが書けそうです。こういう情報は探しても見つからなかったので、とてもありがたいです。同じようなことで困っている人のために、「テストが書けない人のAndroid MVP」を紹介しておきます。

そもそも、MVPとは何でしょうか。MVPは、Model、View、Presenterの略です。Modelは、データの操作を行います。Viewは、AndroidではActivityやFragmentで、画面の表示に関する操作を行います。PresenterはModelとViewをつなぎ、ビジネスロジックを受け持ちます。MVPでは、インターフェースを介してこれらが緩やかに結びついています。本書では、MVPそれぞれの役割について、以下のように記述されています。

  • Model:Presenterから使用されるコンポーネントで、ネイティブアプリではリポジトリーであることが多く、Viewが必要とするデータのCRUD操作などを行う。
  • View:クリックイベントなどをPresenterに伝える。自らが公開しているView更新のインターフェースをPresenterから呼びださせて、画面描画系の処理のみを記述する。
  • Presenter:Viewからイベントを受け取り、必要なModelを操作して処理を行う。その結果をViewに伝え画面の操作を行う。ビジネスロジックはここに集約される。

それで、Presenterをどのように実装すればテスタブルになるのかというと、ポイントはPresenterから具象クラスへの依存を取り除くことです。Presenterの中でstaticメソッドを呼ばず、インスタンスを生成せず、DIを行えば、PresenterはViewやModelに対する依存がなくなり、テスタブルになります。

極端に言えば、Presenterの中で静的メソッドである「static」の呼び出しや、インスタンス生成の「new」という文字を書かず、依存オブジェクトは全てPresenterのコンストラクタで注入すれば、Presenterはテストを書くことができます。これを意識するだけで、PresenterはView層とリポジトリー(Model)層から完全に切り離すことができます。

また、UnitTestの対象は以下の4つです。これらをPresenterに押し込んで、UnitTestを行うことが、アプリの品質を向上させる近道となります。

  • 条件分岐
  • ループ
  • 操作
  • ポリモフィズム

出来上がったPresenterは以下のようになります。ロジックとViewの操作が綺麗に分離されています。また、依存性を注入していることにより、テスタブルです。

class MainPresenter(
    private val view: MainContract.View,
    private val registerApi: RegisterApi,
    private val validator: Validator) : MainContract.Presenter {

    val registerCallback = object : RegisterApi.Callback {
        override fun onSuccess() {
            view.showRegisterSuccess()
        }

        override fun onFailure(error: String) {
            view.showRegisterError(error)
        }
    }

    override fun clickRegisteredButton(mailAddress: String, password: String) {
        if (!validator.validatePassword(password)) {
            view.showValidateError()
            return
        }
        if (!validator.validateMailAddress(mailAddress)) {
            view.showValidateError()
            return
        }
        registerApi.register(mailAddress, password, registerCallback)
    }

    override fun mailAddressFormatCheck(mailAddress: String) {
        if (!validator.validateMailAddress(mailAddress)) {
            view.showMailAddressFormatError()
        } else {
            view.dismissMailAddressFormatError()
        }
    }
}

テストが書けない人のAndroid MVP、とても良い本なのでテストが書けなくて悩んでいる方におすすめです。