I need something similar to C# NUnit TestCase scenario with fixed expected results.
I've already found this question on SO which has great solutions but they are for Java only and as suggested in some of the answers I followed this tutorial, but simply converting it to Kotlin doesn't work.
@RunWith(value = Parameterized.class)
public class EmailIdValidatorTest {
private String emailId;
private boolean expected;
public EmailIdValidatorTest(String emailId, boolean expected) {
this.emailId = emailId;
this.expected = expected;
}
@Parameterized.Parameters(name= "{index}: isValid({0})={1}")
public static Iterable<Object[]> data() {
return Arrays.asList(new Object[][]{
{"mary@testdomain.com", true},
{"mary.smith@testdomain.com", true},
{"mary_smith123@testdomain.com", true},
{"mary@testdomaindotcom", false},
{"mary-smith@testdomain", false},
{"testdomain.com", false}
}
);
}
@Test
public void testIsValidEmailId() throws Exception {
boolean actual= EmailIdUtility.isValid(emailId);
assertThat(actual, is(equalTo(expected)));
}
}
So what is the correct way to write Kotlin parametrized unit tests with JUnit?
Following this amazing tutorial, we can implement it in Kotlin language in this way:
First of all convert the EmailIdUtility class into Kotlin:
object EmailIdUtility {
fun isValid(email: String): Boolean {
val regex =
"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$"
val pattern = Pattern.compile(regex)
val m = pattern.matcher(email)
return m.matches()
}
}
Then convert the EmailIdValidatorTest into Kotlin
@RunWith(value = Parameterized::class)
class EmailIdValidatorTest(
private val email: String,
private val expected: Boolean)
{
@Test
fun testIsValidEmailId() {
val actual = EmailIdUtility.isValid(email)
assertEquals(expected, actual)
}
companion object {
@JvmStatic
@Parameterized.Parameters(name = "{index}: isValid({0})={1}")
fun data(): Iterable<Array<Any>> {
return arrayListOf(
arrayOf("mary@testdomain.com", true),
arrayOf("mary.smith@testdomain.com", true),
arrayOf("mary_smith123@testdomain.com", true),
arrayOf("mary@testdomaindotcom", false),
arrayOf("mary-smith@testdomain", false),
arrayOf("testdomain.com", false)
).toList()
}
}
}
Remember to add
@JvmStaticin thedata()method, otherwise you will get the error: java.lang.Exception: No public static parameters method on class com.example.testapp.dev.EmailIdValidatorTest
EASIER WAY
If you can use another library (working in Android too) I suggest you to add JUnitParams to your test dependencies, in Android it could be:
testImplementation "pl.pragmatists:JUnitParams:1.1.1"
Then you could convert the above class in this way:
@RunWith(JUnitParamsRunner::class)
class EmailIdValidatorTest {
@Test
@Parameters(value = [
"mary@testdomain.com, true",
"mary.smith@testdomain.com, true",
"mary_smith123@testdomain.com, true",
"mary@testdomaindotcom, false",
"mary-smith@testdomain, false",
"testdomain.com, false"
])
fun testIsValidEmailId(email: String, expected: Boolean) {
val actual = EmailIdUtility.isValid(email)
assertEquals(expected, actual)
}
}
which for me is a lot easier than the JUnit way.
For more examples on how to use JUnitParams you can check the link.
With JUnit 5 this is a lot easier but currently JUnit 5 is not supported for Android tests if you don't use Android-JUnit 5 too.
I know you're using JUnit 4, but if you consider to update to JUnit 5, you can use @TestFactory annotation to execute parametrized unit test.
In your case that would result in a test class like this:
import org.junit.jupiter.api.DynamicTest
import org.junit.jupiter.api.TestFactory
internal class EmailIdValidatorTest {
@TestFactory
fun `test email id validity`() =
listOf(
"mary@testdomain.com" to true,
"mary.smith@testdomain.com" to true,
"mary_smith123@testdomain.com" to true,
"mary@testdomaindotcom" to false,
"mary-smith@testdomain" to false,
"testdomain.com" to false
).map {
dynamicTest("email ${it.first} should be ${if (it.second) "valid" else "not valid" }") {
val actual = EmailIdUtility.isValid(it.first)
assertEquals(expected, actual)
}
}
}