While debugging a Parameterized test, I realized the test wouldn't run if the parameters were passed as a List of Lists (List<List<Any>>
), yet worked fine with a List of Arrays (List<Array<Any>>
).
Example classes:
import com.google.common.truth.Truth
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
class TestWithList(val input: List<Int>, val output: Int) {
companion object {
@JvmStatic
@Parameterized.Parameters
fun data(): List<List<Any>> =
listOf(
listOf(
listOf(1, 4, 3, 2),
4
)
)
}
@Test
fun `empty test`() {
Truth.assertThat(true).isTrue()
}
}
Throws
IllegalArgumentException: wrong number of arguments
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
class TestWithArray(val input: List<Int>, val output: Int) {
companion object {
@JvmStatic
@Parameterized.Parameters
fun data(): List<Array<Any>> =
listOf(
arrayOf(
listOf(1, 4, 3, 2),
4
)
)
}
@Test
fun `empty test`() {
assertThat(true).isTrue()
}
}
Runs perfectly.
Why does passing a List
pass the wrong number of arguments?
I'm not familiar with parameterized testing with JUnit. However, I did find this. If you look at the method signature:
public static Collection<Object[]> data()
In Kotlin, that is:
fun data() : Collection<Array<Any>>
You'll see it's a Collection, containing an Object array. List
is a Collection, but a List
is not an Array
. It's a two-dimensional system, where the second dimension contains the arguments you want to pass, including length.
Since they use an Array in the docs, I'd suggest you do so to.
Recently, they introduced single parameters. The signature looks like this:
@Parameters
public static Iterable<? extends Object> data()
And again, List is an Iterable. However, in your case, this is the one you ended up calling without an array.
As a result, you passed a single argument to a two-argument constructor, which threw the exception. You passed an Iterable>, which is not Collection<Array<Any>>
. Which means you instead ended up creating a system that works for a single argument. Since the constructor takes two arguments, you get the exception. You pass a single argument (the List), but you need two arguments.
This is why using an array works, but a List doesn't; if you use a list, it assumes you have a single argument constructor, where as with an Array, it takes multiple. As far as I can tell, JUnit doesn't support Lists instead of Arrays for multi-argument constructors.
TL;DR: The reason arrays work and list don't is because it thinks the List is an argument for a single-argument constructor, where as with an Array, it could be any number of arguments.