Kotlin の Object を Mockito + PowerMock でモックする
この記事では、Kotlin の Object という機能を使った部分をモックする手法について説明しています。
TL; DR
- PowerMock を使うと Kotlin の Object をモックできる
-
@JvmStatic を付けると
static
メソッドとしてコンパイルされる
- サンプルプロジェクト: https://github.com/pine613/kotlin-object-mock-sample
Kotlin とは ?
static
メソッドとしてコンパイルされるKotlin (ことりん) は IntelliJ IDEA で有名な JetBrains 社が開発している Java との相互運用性を持ったプログラミング言語です。
Kotlin の Object とは ?
Singleton パターン を簡潔に記述することができる記法です。明示的にインスタンスを生成するコードなどを書かずに Singleton が実現できるため、定形コードを削減することができます。
内部的な実装は、Java で Singleton を実装した場合とほとんど変わりません。
テスト対象のクラス
モックしたい Object
foo
メソッドと bar
プロパティが存在する Foo
オブジェクトです。
Kotlin のプロパティである bar
は Java でいう getBar
と setBar
に対応する getter/setter を裏で生成します。
object Foo {
fun foo(): String {
return "foo"
}
val bar: String by lazy { "bar" }
}
モック対象 Object を使ってるクラス
object
で宣言したものは、Singleton として直接呼び出せます。今回は、この Bar
クラスをテストする時に Foo
クラスをモックしテストする話をします。
class Bar {
fun foo(): String {
return Foo.foo()
}
val bar: String
get() = Foo.bar
}
テストの際に使うライブラリ
テストコード
以下で解説しているコードは、サンプルプロジェクトして GitHub 上に公開されていますので、実際に動かしてみる場合はそちらをご利用ください。
Foo
クラスに対するテスト
普通に JUnit と kotlin.test を使って書きます。
import org.junit.Test
import kotlin.test.assertEquals
class FooTest {
@Test
fun foo() {
assertEquals("foo", Foo.foo())
}
@Test
fun bar() {
assertEquals("bar", Foo.bar)
}
}
Bar
クラスに対するテスト
前準備として、Foo
クラスをモックでテスト可能にするために @JvmStatic
アノテーションを追加します。これにより、Foo
クラスに対しての static
メンバとしてコードが生成されます (詳細後述)。
object Foo {
@JvmStatic
fun foo(): String {
return "foo"
}
@JvmStatic
val bar: String by lazy { "bar" }
}
Mockito と PowerMock を合わせて使います。PowerMock には Mockito 向けのインターフェイスが用意されているので、それを用います。
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner
import kotlin.test.assertEquals
@RunWith(PowerMockRunner::class)
@PrepareForTest(Foo::class)
class BarTest {
@Test
fun foo() {
// Foo.foo() のモック処理
PowerMockito.mockStatic(Foo::class.java)
Mockito.`when`(Foo.foo()).thenReturn("xxx_foo")
// モックを用いて Bar クラスをテスト
assertEquals("xxx_foo", Bar().foo())
// モックが呼ばれたことを検証
PowerMockito.verifyStatic()
Foo.foo()
}
@Test
fun bar() {
// Foo.getBar() のモック処理
// (Kotlin のプロパティは、Java の getter/setter に該当)
PowerMockito.mockStatic(Foo::class.java)
Mockito.`when`(Foo.bar).thenReturn("xxx_bar")
assertEquals("xxx_bar", Bar().bar)
// モックが呼ばれたことを検証
PowerMockito.verifyStatic()
Foo.bar
}
}
補足
@RunWith(PowerMockRunner::class)
このテストクラスを PowerMock を使って実行することを指定します。
@PrepareForTest(Foo::class)
PowerMock で弄るクラスを指定します。PowerMock でモック化するには、事前にここで指定する必要があります。
PowerMockito.mockStatic(Foo::class.java)
クラスの static
メンバをモック可能にします。このメソッドを実行後に Mockito で弄ることができるようになります。
PowerMockito.verifyStatic()
static
メンバが呼ばれたかどうか検証を行います。このメソッドを実行後、モックのメソッドを期待する引数で呼び出すことで検証されます。
@JvmStatic
アノテーションの働き
Kotlin の Object は、コンパイルすると Singleton パターンのクラスとなります。例えば、以下の Example.kt
をコンパイルすると、
object Example {
fun foo(): String {
return "foo"
}
}
次のようなクラスが生成されます。
public final class Example
{
public final String foo()
{
return "foo";
}
private Example()
{
}
public static final Example INSTANCE = (Example)this;
/**
* @deprecated Field INSTANCE$ is deprecated
*/
public static final Example INSTANCE$ = (Example)this;
static
{
new Example();
}
}
Kotlin で Example.foo()
と記述した場合に実際に呼び出されるのは Example.INSTANCE.foo()
となります。
この状況で Example
をモックするには、INSTANCE
変数に再度モックしたインスタンスを設定してあげる必要がありますので、モックする手間が増えます (モックは可能ですが)。
@JvmStatic
アノテーションを付加した場合、以下のように foo
が static
メソッドしてコンパイルされます。
public final class Example
{
public static final String foo()
{
return "foo";
}
private Example()
{
}
public static final Example INSTANCE = (Example)this;
/**
* @deprecated Field INSTANCE$ is deprecated
*/
public static final Example INSTANCE$ = (Example)this;
static
{
new Example();
}
}
この場合、Kotlin からは直接 static
メソッドが呼ばれるようにコンパイルされますので、対象の static
メソッドをモックしてあげるだけで OK です。
Author And Source
この問題について(Kotlin の Object を Mockito + PowerMock でモックする), 我々は、より多くの情報をここで見つけました https://qiita.com/pinemz/items/a9e619ce4cb51b729655著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .