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[][]{
{"[email protected]", true},
{"[email protected]", true},
{"[email protected]", 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?
There are five steps that you need to follow to create a parameterized test. Annotate test class with @RunWith(Parameterized. class). Create a public static method annotated with @Parameters that returns a Collection of Objects (as Array) as test data set.
JUnit 5, the next generation of JUnit, facilitates writing developer tests with shiny new features. One such feature is parameterized tests. This feature enables us to execute a single test method multiple times with different parameters.
Test parameterization is a type of data-driven testing that allows you to execute the same test, multiple times using different parameters. Xray Cloud has a parameterized tests feature, that executes the same test with different input values, multiple times, without ever having to clone or replicate it.
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("[email protected]", true),
arrayOf("[email protected]", true),
arrayOf("[email protected]", true),
arrayOf("mary@testdomaindotcom", false),
arrayOf("mary-smith@testdomain", false),
arrayOf("testdomain.com", false)
).toList()
}
}
}
Remember to add
@JvmStatic
in 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 = [
"[email protected], true",
"[email protected], true",
"[email protected], 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(
"[email protected]" to true,
"[email protected]" to true,
"[email protected]" 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)
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With