sky’s 雑記

主にAndroidとサーバーサイドの技術について記事を書きます

Spekラムダ内でKoinモジュールをinjectする

Androidユニットテストネタ.

TL;DL

KoinTestを継承したRootクラスと、それをレシーバとするラムダを引数に持つ抽象クラスを実装する。

class KoinRoot(val root: Root) : KoinTest, Root by root

abstract class KoinSpek(koinSpec: KoinRoot.() -> Unit) : Spek({
    koinSpec.invoke(KoinRoot(this))
})

object TestSpec: KoinSpek({
    beforeEachTest {
        startKoin {
            modules(listOf(testAppModule))
        }
    }

    val viewModel: TestViewModel by inject()
})

導入

  • Spekについて

QA体制が十分でないときや強力なプロダクトオーナーが不在のときにバグを減らす手段としてビヘイビア駆動開発(BDD)は結構有効だと思っていて、そういう現場でテストフレームワークとしてSpekを選択するのはアリだと思っている。

  • Koinについて

Dagger2よりシンプルでラーニングコストが低いので熟練のAndroidエンジニアが少なくアプリケーションの要件も複雑でない場合にKoinをDIコンテナとして選択するのはアリだと思っている。

両方とも開発体制が整っていない現場で選択肢となりうる技術かなと思っているが組み合わせて使おうと思うと途端にドキュメントが減って、逆に辛いことになること学んだわけだが、しばらくはこの組み合わせでやっていこうと思っているので備忘録的に残しておく。

概要

KoinTest

/**
 * Get an instance from Koin
 */
inline fun <reified T> KoinTest.get(
    qualifier: Qualifier? = null,
    noinline parameters: ParametersDefinition? = null
): T =
        getKoin().get(qualifier, parameters)

/**
 * Lazy inject an instance from Koin
 */
inline fun <reified T> KoinTest.inject(
    qualifier: Qualifier? = null,
    noinline parameters: ParametersDefinition? = null
): Lazy<T> = lazy { get<T>(qualifier, parameters) }

Spek

abstract class Spek(val root: Root.() -> Unit)


@SpekDsl
interface Root : GroupBody {
    fun registerListener(listener: LifecycleListener)
    fun include(spek: Spek) = spek.root(this)
}

実装

KoinTestを継承したRootクラスと、それをレシーバとするラムダを引数に持つ抽象クラスを実装する。

Spekはレシーバ付きラムダRootをコンストラクタに持つabstract class. RootがKoinTestを継承するとSpekオブジェクト内でKoinコンポネントのinjectが可能になるので、 KoinTestを継承しRootに処理を移譲するKoinRootを定義する。

class KoinRoot(val root: Root) : KoinTest, Root by root

上記KoinRootをレシーバとするラムダを引数に持ちレシーバ付きラムダを実行するabstract classを定義する。

abstract class KoinSpek(koinSpec: KoinRoot.() -> Unit) : Spek({
    koinSpec.invoke(KoinRoot(this))
})

参考

高階関数とラムダ - Kotlin Programming Language

Spekではじめるユニットテスト

SpekでUnitTestを書こう / unit-test-with-spek - Speaker Deck