Last time (“Extracting” in References), we looked at why you’d use parameterized tests, to reduce duplication, improve clarity, and improve test quality. This time we’ll look at an example parameterized test in three languages: Java, Kotlin, and Swift.
Java Example
JUnit, the standard test package, supports parameterized tests directly. Your parameterized method can get values directly, from an enum, from CSV strings or files, or provided by another method.
Here, we use the latter technique: shortParsesCorrectly()
is the test method, and shortsAsStrings()
provides the data.
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertEquals; public class ParamTest { @ParameterizedTest @MethodSource("shortsAsStrings") void shortParsesCorrectly( String input, short expected, String why) { var actual = Short.valueOf(input); assertEquals(expected, actual, why); } private static Stream<Arguments> shortsAsStrings() { return Stream.of( Arguments.of("000", Short.valueOf((short) 0), "zero"), Arguments.of("-32768", Short.MIN_VALUE, "minimum"), Arguments.of("32767", Short.MAX_VALUE, "maximum"), Arguments.of("010", Short.valueOf((short) 10), "decimal even with leading 0"), Arguments.of("+32767", Short.MAX_VALUE, "max with leading +") ); } }
Kotlin Example
Kotlin can also use JUnit’s parameterized support. It uses companion object
as an analog to Java’s static
, with @JvmStatic
for interoperability. Notice that I’ve used the “why” in the @ParameterizedTest
‘s name
attribute.
import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.MethodSource import java.util.stream.Stream class PTest { @ParameterizedTest(name = "Short: {2}") @MethodSource("shortsAsStrings") fun shortParsesCorrectly( input: String, expected: Short, why: String) { val actual = input.toShort() assertEquals(expected, actual) } companion object { @JvmStatic fun shortsAsStrings(): Stream<Arguments> { return Stream.of( Arguments.of("000", 0.toShort(), "zero"), Arguments.of("-32768", Short.MIN_VALUE, "minimum"), Arguments.of("32767", Short.MAX_VALUE, "maximum"), Arguments.of("010", 10.toShort(), "decimal even with leading 0"), Arguments.of("+32767", Short.MAX_VALUE, "max with leading +") ) } } }
Swift Example
Unlike Java, Swift doesn’t have parameterized tests in its standard test library XCTest. We can make our own parameterized tests: hold the data values in an array and loop over them. (This approach is what I used in “Parameterized Unit Testing” in References, and may be the start of a framework.)
import XCTest class PDemoTests: XCTestCase { struct Example<Input, Output> { var input: Input var output : Output var message: String var line: Int init(input: Input, output: Output, _ message: String = "", _ line: Int = #line) { self.input = input self.output = output self.message = message self.line = line } func msg() -> String { return "Line \(line): \(message)" } } func testStringToInt16() { [ Example(input: "000", output: Int16(0), "zero"), Example(input: "-32768", output: Int16(INT16_MIN), "min value"), Example(input: "32767", output: Int16(INT16_MAX), "max value"), Example(input: "010", output: Int16(10), "decimal value"), Example(input: "+32767", output: Int16(INT16_MAX), "leading +") ].forEach { example in let actual = Int16(example.input) XCTAssertEqual(example.output, actual, example.msg()) } } }
I used a helper class, but a tuple (anonymous record) would have worked fine too.
Conclusion
Whether your language has a parameterized test framework (Java, Kotlin), or you have to build your own parameterized tests (Swift), you can get the benefits of this style of test.
References
“Extracting Parameterized Unit Tests“, by Bill Wake. Retrieved 2021-09-12.
“Guide to JUnit 5 Parameterized Tests“, by Ali Dehghani. Retrieved 2021-09-13.
“Parameterized Unit Testing“, by Bill Wake. Retrieved 2021-09-12.