はじめに
Androidでインストゥルメント化単体テストを作成するとき、@get:Rule
を使ってテストを書いたことはありませんか?
@HiltAndroidTest
class AppTest {
private val hiltRule = HiltAndroidRule(this)
private val composeTestRule = createAndroidComposeRule<MainActivity>()
@get:Rule
val rule: RuleChain = RuleChain
.outerRule(hiltRule)
.around(composeTestRule)
...
}
この、@get:Rule
やRuleChain.outerRule().around()
がよくわからない状態で、今まではテストを書いてきました。
ということで今回は、@get:Rule
とかのRuleってなんぞやということをまとめていきたいと思います。
Ruleとは何なのか
公式ドキュメントにて、次の一文を発見しました。
JUnit ルールはテストの柔軟性を高め、必要なボイラープレート コードを削減します。
https://developer.android.com/training/testing/junit-rules?hl=ja
Guide to JUnit 4 Rulesの記事内で、次のような記述を見つけました。
JUnit 4 rules provide a flexible mechanism to enhance tests by running some code around a test case execution. In some sense, it’s similar to having @Before and @After annotations in our test class.
そして、次の一文。
By using a rule, we can have everything isolated in one place and reuse the code easily from multiple test classes.
https://www.baeldung.com/junit-4-rules
つまり、今まで@Before
や@After
を使って行っていた処理をルールとしてまとめることで、いろいろなテストから呼び出せるようになり再利用できるようになる。これこそがルールのメリットということです。
例えば、@Before
でデータベースに接続して、@After
で接続を解除するという処理をルールとしてまとめることで、いろいろなテストで何度も同じ処理を書かずに済むといったことが可能となります。
RuleChainとは何なのか
実は、RuleChainもルールです。なので、ドキュメントなどではThe RuleChain rule ...
などと書かれたりします。
このRuleChainを使うと、ルールの順序づけを行うことができるようになります。
RuleChainが一番使われるユースケースは、複数のルールを順序通りに実行した上で各テストケースを実行したい場合です。
RuleChainを使わなくても、テストに複数のルールを配置することは可能です。しかし、その際に実行されるルールの順番はランダムになります。この順番をコントロールするために、RuleChainは使われます。
最初に実行したいルールをouterRule()
を使って指定します。次に続くルールは順番にaround()
を呼び出しすことで繋げていきます。
private val hiltRule = HiltAndroidRule(this)
private val composeTestRule = createAndroidComposeRule<MainActivity>()
@get:Rule
val rule: RuleChain = RuleChain
.outerRule(hiltRule)
.around(composeTestRule)
ちなみに、@get:Rule
と@Rule
の違いは?
Javaでは、@Rule
を使ってルールを指定します。
しかし、Kotlinで同じように@Rule
を使おうとするとエラーが出てしまうようです。
Kotlinでは、@get:Rule
を使ってルールを宣言することで、getterプロパティに対して@Rule
アノテーションを適用するという意味を持たせることができます。
これにより、エラーの発生を抑えて安心してルールを使えるようになります。
...省略
class Tests {
// apply @Rule annotation to property getter
@get:Rule val tempFolder = TemporaryFolder()
@Test fun simple() {
val f = tempFolder.newFile()
assertEquals(42, getTheAnswer())
}
}
まとめ
久しぶりに、Androidのインストゥルメント化単体テストを書こうと思ったときに、過去に自分が書いたテストに@get:Rule
が存在したため、ルールってなんだっけって思ったところがこの記事の出発点でした。
今回はあくまで用語解説に過ぎないので、いつかルールを自分で書いてみた記事も公開できればよいなと思います。
参考にした記事