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.
