🤜

Junit4でパラメータを色々変えたUIテストをしたい

3 min read

キーワード

UI Test,JUnit4,繰り返し(loop),引数(argument),パラメータ(parameter)

したいこと

TextFieldに入力された文字列に応じてUIが変わるViewを実装をしたときに、このViewが予期した動きをするか調べたい。
どんな感じでやりたいかというと、以下のような感じ。

以下のコードは動きません。


val valueTest = listOf(
	"Nyao",
	"Wan",
	"ChunChun",
)

@Test
fun manageTest() {
	valueTest.forEach { val ->
		inputTest(val)
	}
}

@Test
fun inputTest(str: String) {
	composeTestRule.onNodeWithText("Input").performTextInput(str)
	composeTestRule.onNode(expectValue(str)).assertIsDisplayed()
}

fun expectValue(str: String): String {
  var result = ""
  if(str == "Nyao") {
	  result = "(ΦωΦ)"
  } else if (str == "Wan") {
	  result = "U^ェ^U"
  } else {
	  result = "(´・ω・`)"
  }
  return result
}

やり方

Parameterizedテストでやる方法

yanzmさんの記事[1]を参考に、テストのクラスのコンストラクタ引数に入れてしまう方法です。

テストに合わせたViewを記事用に実装するのが面倒だったため、以下は動作未実証です。
@RunWith(Parameterized::class)をclassにつける、classにコンストラクタ引数をつける、companion objectのブロックを実装する、@Testアノテーションの関数に引数を入れない。これらを抑えてもらえれば問題ないと思います。

@RunWith(Parameterized::class)
class InputViewKtTestPara (private val str: String) {

	@Test
	fun inputTest() {
		composeTestRule.onNodeWithText("Input").performTextInput(str)
		composeTestRule.onNode(expectValue(str)).assertIsDisplayed()
	}
	
	companion object {
		@Parameterized.Parameters
		@JvmStatic
		fun data(): Iterable<String> {
		    return listOf(
			"Nyao",
			"Wan",
			"ChunChun",
		    )
		}
	    }
	fun expectValue(str: String): String {
		  var result = ""
		  if(str == "Nyao") {
			  result = "(ΦωΦ)"
		  } else if (str == "Wan") {
			  result = "U^ェ^U"
		  } else {
			  result = "(´・ω・`)"
		  }
		  return result
	}
}

このやり方だと、クラスでいくつかのメソッドを持った時に、各メソッドに違う値を入れたい時に少し苦労します。しかし、単一の種類のデータであれば、これが一番楽だと思います。

@Testアノテーションを付けないmethodを組み合わせる

例えば、"Wan"と入力した後に"Nyao"と入力した結果をテストしたい、など入力値の組み合わせや、methodごとに異なる種類のデータを入れたいときは、もっと柔軟にしたほうが良いことがあります。今回は、3つの値なので、1つの値を入れたときのテストは3種類、2つの値を入れるときは順序考慮で6通り、3つの値を入れるときは順序考慮で6通りあり、合わせて15通りあることになります。これを配列で用意するのは現実的ではなく、loop関数で自動で行いたいこともあるでしょう。
その時は@Testアノテーションを付けないmethodを用意して、実行するのが良いと思います。

テストに合わせたViewを記事用に実装するのが面倒だったため、以下は動作未実証です。
@Testアノテーションを付けない関数の引数に入れるという点を抑えてもらえれば問題ないと思います。

val valueTest = listOf(
	"Nyao",
	"Wan",
	"ChunChun",
)

@Test
fun manageTest() {
	valueTest.forEach { val ->
		inputTest(val)
	}
}

fun inputTest(str: String) {
	composeTestRule.onNodeWithText("Input").performTextInput(str)
	composeTestRule.onNode(expectValue(str)).assertIsDisplayed()
}

fun expectValue(str: String): String {
  var result = ""
  if(str == "Nyao") {
	  result = "(ΦωΦ)"
  } else if (str == "Wan") {
	  result = "U^ェ^U"
  } else {
	  result = "(´・ω・`)"
  }
  return result
}
脚注
  1. Android で Parameterized テスト(JUnit4, Robolectric)を行う / yanzm http://y-anz-m.blogspot.com/2018/03/android-junit4-parameterized.html (2022-01-04閲覧) ↩︎

Discussion

ログインするとコメントできます