Parameterize

Parameterize is a multiplatform Kotlin library introducing a concise, idiomatic style of parameterizing code. Having
parameters be declared within the logic, potentially conditionally or with dynamic arguments, it's possible to model
complicated control flow scenarios much more cleanly.
parameterize {
val letter by parameter('a'..'z')
val primeUnder20 by parameterOf(2, 3, 5, 7, 11, 13, 17, 19)
val computedValue by parameter { slowArgumentsComputation() }
}
With its default behavior, parameterize is strictly an alternative syntax to nested for loops, with loop variables
defined within the body instead of up front, and without the indentation that's required for additional inner loops.
In addition to its default behavior, parameterize has a configuration with options to decorate its iterations, handle
and record failures, and summarize the overall loop execution. The flexibility parameterize offers makes it suitable
for many different specific use cases, including built in ways to access the named parameter arguments when a failure
occurs, recording failures while continuing to the next iteration, and throwing comprehensive multi-failures that list
recorded failures with parameter information.
Parameterized Testing
With parameterized testing being the motivating use case for this library, parameterize can be used to cleanly and
more idiomatically cover edge cases while testing. As an example, here is a test that succinctly covers all the possible
ways a substring can be contained within a string, running the parameterize block once for each case:
val string = "prefix-substring-suffix"
val string = "substring-suffix"
val string = "prefix-substring"
val string = "substring"
fun a_string_should_contain_its_own_substring() = parameterizeTest {
substring =
prefix parameterOf(, )
suffix parameterOf(, )
string =
assertTrue(string.contains(substring), )
}
If any of the test cases don't pass, the failures will be wrapped into an Error detailing the parameters with their
arguments and parameter names for each, plus support for JVM tooling with
expected/actual value comparison
and multi-failures:
The parameters are designed to be flexible, being able to depend on other parameters, be declared conditionally, or even
used in a loop to declare multiple parameters from the same property. Features which are especially useful for covering
edge/corner cases:
@Test
fun an_int_should_not_equal_a_different_int() = parameterizeTest {
val int by parameterOf(0, 1, -1, Int.MAX_VALUE, Int.MIN_VALUE)
val differentInt by parameterOf(int + 1, int - 1)
assertNotEquals(int, differentInt)
}
Test Suite Examples
Setup
Modules
| Artifact | Description |
|---|
parameterize-api | Library primitives, including the interface and functions. |
Gradle
plugins {
kotlin("jvm") version "2.2.21"
}
repositories {
mavenCentral()
}
dependencies {
implementation("com.benwoodworth.parameterize:parameterize-core:$parameterize_version")
}
A note about stability
While Parameterize is in beta, there may be source/binary/behavioral changes in new minor (v0.#.0) releases. Any
breaking changes will be documented on release, with
automatic replacements
for source-breaking changes provided where possible.
That said, the library is thoroughly tested, and the parameter DSL is unlikely to drastically change, with most of the
library's evolution expected to be isolated to configuration. So in scenarios where binary compatibility isn't a
concern, and changes to configuration are acceptable, I consider Parameterize ready to be used in the wild. Of course
exercise caution with these earlier releases, as they have not yet been battle tested. But as a strong believer of
dogfooding in software, I am already using it for testing in projects of my own. And in case of any major bugs, I will
make sure they are addressed in a timely manner.
I designed the library to address pain points I found in the rigidness of other parameterized/property-based testing
libraries, and have been very happy with some new patterns that have emerged from the flexible code that Parameterize
enables. I'm planning on documenting these at some point, and encourage discussion and code sharing in the Slack channel
linked at the top :)