前回の記事でも少し書きましたが、7/1(金)に第3回Kotlin勉強会 @ Sansanで発表をしてきました。

発表の際に使用したスライドがこちらです。

スライドだけだと伝わりづらい部分もあるかと思いますので、この記事でも内容を説明していきたいと思います。

Androidのテスト

AndroidのテストにはJavaVMで実行するテスト(Local Unit Tests)と、端末上で実行するテスト(Instrumented Unit Tests)の2種類があります。

前者はtestディレクトリ、後者はandroidTestディレクトリにテストコードを追加していきます。

今回の発表では、そこまで踏み込んだ内容はないこともあり、手軽に実行できるLocal Unit Testsを軸に説明を進めました。

Kotlinでテストコードを書く準備

Kotlinのプラグインなどを利用して、Kotlinを使えるようにした後、まずはapp/build.gradleのsourceSetsを編集します。

通常はsrc/test/javaディレクトリ以下に、テストコードを追加しますが、src/test/kotlinディレクトリに追加してもテストコードを読み込めるようにするための設定です。

ちなみにこちらの設定は任意です。KotlinとJavaの配置場所を明確に分けたい場合は利用すると良いでしょう。

※ちなみにAndroid Studioの「Android」ビューではjavaディレクトリなのかkotlinディレクトリかがわからないので、こちらを多用する方(チーム)はディレクトリ構成をどうするか少し考えた方が良さそうです

スクリーンショット_2016-07-03_7_35_42

普通にテストコードを書いてみる

プロジェクトを作った時点で最初から用意されているJavaで書かれたテストコードは以下のようなものです。

これをKotlinで書きなおして実行してみましょう。

publicが取れて、関数宣言がfunになったぐらいの違いですね。

これでテストを実行してみると、普通に成功することを確認できます。

pasted-image

現実的にはmockitoが必要

テストを書き進めると必要になってくるのがmockitoのようなモックライブラリです。

mockitoでは以下のような機能をはじめとして多くの持っています。

  • メソッドの返却値を差し替える
  • オブジェクトの一部メソッドだけを差し替える
  • 呼び出しを検証する

mockitoを使うためにはapp/build.gradleなどにdependenciesを追加するのが手軽で良いでしょう。

Kotlinでmockitoを使う

それではKotlinでmockitoを利用してみましょう。

まずはContext.getPackageNameをモックした例です。

この例では、context.packageNameを呼びだすと、必ず”shoma2da"という文字列が返却されるようにオブジェクトがモック化されています。

Kotlinで書かれたクラスをテストする

次にKotlinで書かれたUserクラスをテストする場合を考えてみましょう。

産まれた年をインスタンス生成時のパラメータとして受け取り、それをもとにgetAgeというメソッドで数え年を返却しています。(簡単な例なのでvalでも一向に構わないのですが、テスト用のクラスとして考えてください)

このUserクラスに対するテストを書いてみます。

このテストではgetAgeメソッドの返却値として必ず1が返ってくるようにモックを行っています。

 

Contextをモックした場合と大差ないコードですが、このテストを実行してみるとエラーが発生します。

これは以下のような理由からです。

  • Mockitoは、クラスを継承してメソッドを書き換えている
  • Kotlinではopen修飾子を付けないかぎりクラスもメソッドもfinalが付いている
    →継承もOverrideもできない!

どのように対処していくか

このように、Kotlinのクラスをテストしようとした場合に、クラスやメソッドをオーバライドできない問題に対して以下3つの方法が上げられます。

  1. openを付ける
  2. テスト対象クラスをinterfaceにする
  3. PowerMockを使う

1. openを付ける

まず最初はUserクラス側にopen修飾子を付けてしまう方法です。

テストコード側には一切変更はありません。

この方法はおそらく一番手軽に対応できる一方、Kotlinがせっかく言語仕様で守ってくれている安全性を破壊してしまっています…。

2.テスト対象クラスをinterfaceにする

次にUserを思いきってinterfaceにしてしまう方法です。

オブジェクト指向的にはキレイな方法ですし、Class Delegationなども使いやすくなっていきます。

一方で記述量はそこそこ多いので、たくさんのクラスに対応していくのは少し面倒かもしれません…

3. PowerMockを使う

最後がPowerMockを使う方法です。

PowerMockはfinalやprivateなど、通常は変更できない・触れられない部分についてもモック化などが行える、mockitoの進化版のようなライブラリです。

この方法では、PowerMockの導入とテストコードの修正が必要になります。

この方法では変更がテストコードのみで済みます。

一方で、PowerMockはある意味「なんでもあり」のモックライブラリですので、慣れない方が使うと肝心のプロダクション側のクラス設計が適当になってしまうなど、悪影響が出てしまうことが懸念でしょうか…。

 

3つの対処法を提示してきましたが、テストコード内だけで対応が済むPowerMockを使う方法が優勢かな?というふうに感じています。

なにか知見などありましたらぜひ教えて下さい。

感想

人数規模もちょうどよく、発表前からビールが飲めるなど非常に楽しいLTでした!

Kotlinエバンジェリスト(Jetbrains黙認)のたろうさんとお話させていただいたのですが、以前から認知してもらえていたようで、ものすごく嬉しかったです。

次回も参加します!

Let’s Enjoy Kotlin life!

follow us in feedly

↓↓Kindle本を出しました