Kotlin DSL Exp
Fixture Monkey utilizes Kotlin’s DSL feature to ensure type-safety with expressions. Let’s explore how we can employ Kotlin Exp instead of the standard Java String Expression.
Referencing a property
Suppose we have an object structure similar to the one described earlier, written in both Java and Kotlin:
@Value
public class JavaClass {
String field;
List<String> list;
Nested nestedObject;
List<Nested> nestedObjectList;
@Value
public static class Nested {
String nestedField;
}
}
data class KotlinClass(
val field: String,
val list: List<String>,
val nestedObject: Nested,
val nestedObjectList: List<Nested>
) {
data class Nested(
val nestedField: String
)
}
To use Kotlin Exp to reference a property, you need to use the Exp
or ExpGetter
suffix to the normal Fixture Customization APIs.
Let’s look at the example of customizing properties with Kotlin Exp using setExp()
and setExpGetter()
.
@Test
fun test() {
// given
val fixtureMonkey = FixtureMonkey.builder()
.plugin(KotlinPlugin())
.plugin(JacksonPlugin())
.build()
// when
val javaClass = fixtureMonkey.giveMeBuilder<JavaClass>()
.setExpGetter(JavaClass::getField, "field")
.sample()
val kotlinClass = fixtureMonkey.giveMeBuilder<KotlinClass>()
.setExp(KotlinClass::field, "field")
.sample()
// then
then(javaClass.field).isEqualTo("field")
then(kotlinClass.field).isEqualTo("field")
}
In the code above, we can see that we are using Kotlin’s method reference to select a property.
setExp()
takes an argument of type KProperty
, while setExpGetter()
takes an argument of type KFunction
.
If the class is defined in Java, the expression (e.g. JavaClass::getField) is of type KFunction
because it is a reference to a Java getter.
Therefore you can only use the setExpGetter()
method.
If it is a Kotlin class, the expression (e.g. KotlinClass::field) is KProperty
, so you should use setExp()
.
Referencing a nested property
To access a nested field, the infix functions into
and intoGetter
are used.
into
takes a parameter of type KProperty
, while intoGetter
takes a parameter of type KFunction
.
@Test
fun test() {
// given
val fixtureMonkey = FixtureMonkey.builder()
.plugin(KotlinPlugin())
.plugin(JacksonPlugin())
.build()
// when
val javaClass = fixtureMonkey.giveMeBuilder<JavaClass>()
.setExp(JavaClass::getNestedObject intoGetter JavaClass.Nested::getNestedField, "nestedField")
.sample()
val kotlinClass = fixtureMonkey.giveMeBuilder<KotlinClass>()
.setExp(KotlinClass::nestedObject into KotlinClass.Nested::nestedField, "nestedField")
.sample()
then(javaClass.nestedObject.nestedField).isEqualTo("nestedField")
then(kotlinClass.nestedObject.nestedField).isEqualTo("nestedField")
}
An expression that contains an into or intoGetter operator becomes an ExpressionGenerator
type in fixture monkey.
Both setExp()
and setExpGetter()
) are defined to take ExpressionGenerator types as arguments, so you can use both.
Selecting Properties Using Kotlin DSL Expressions
Selecting the root object:
- Currently Not Supported
Selecting a specific field:
JavaClass::getField // java class
KotlinClass::field // kotlin class
Selecting a nested field:
JavaClass::getNestedObject intoGetter JavaClass.Nested::getNestedField // java class
KotlinClass::nestedObject into KotlinClass.Nested::nestedField // kotlin class
Selecting the n-th element of a collection:
JavaClass::getNestedObjectList["0"] // java class
KotlinClass::nestedObjectList["0"] // kotlin class
Selecting all elements of a collection:
JavaClass::getNestedObjectList["*"] // java class
KotlinClass::nestedObjectList["*"] // kotlin class
Combining expressions to select a nested field:
JavaClass::getNestedObject intoGetter JavaClass.Nested::getNestedField // java class
KotlinClass::nestedObject into KotlinClass.Nested::nestedField // kotlin class