Skip to main content
Version: v1.1.x

Path expressions

What you will learn in this document

  • How to select specific fields or properties of a test object
  • How to reference specific parts of an object using string expressions
  • How to access properties in various structures like nested objects, arrays, and lists

Introduction to Path Expressions

When writing tests, you often need to modify specific fields of your test objects. Path expressions in Fixture Monkey are like GPS coordinates that help you precisely locate and modify any part of your test object.

As a beginner, think of path expressions as a way to "navigate" through your object structure to reach exactly the field you want to change.

Basic Object Structure Example

To understand path expressions, let's use a simple example object:

@Value
public class JavaClass {
String field; // A simple string field
String[] array; // An array of strings
List<String> list; // A list of strings
Nested object; // A nested object
List<Nested> objectList; // A list of nested objects

@Value
public static class Nested {
String nestedField; // A field inside the nested object
}
}

Visual Map of Path Expressions

Think of your object as a tree structure. Each path expression is like directions to a specific location in that tree:

JavaClass / KotlinClass

├── field → "field" // Direct field access

├── array → "array" // The entire array
│ ├── array[0] → "array[0]" // First element in array
│ ├── array[1] → "array[1]" // Second element in array
│ └── all elements → "array[*]" // ALL elements in array (wildcard)

├── list → "list" // The entire list
│ ├── list[0] → "list[0]" // First element in list
│ ├── list[1] → "list[1]" // Second element in list
│ └── all elements → "list[*]" // ALL elements in list (wildcard)

├── object → "object" // The nested object
│ └── nestedField → "object.nestedField" // Field inside nested object

└── objectList → "objectList" // List of nested objects
├── objectList[0] → "objectList[0]" // First object in the list
│ └── nestedField → "objectList[0].nestedField" // Field in first object

├── objectList[1] → "objectList[1]" // Second object in the list
│ └── nestedField → "objectList[1].nestedField" // Field in second object

└── all elements → "objectList[*]" // ALL objects in the list
└── nestedField → "objectList[*].nestedField" // Field in ALL objects

Simple Path Expressions Guide

String path expressions work identically in Java and Kotlin. The examples below show both languages.

1. Selecting the Root Object

To select the entire object itself, use "$":

ArbitraryBuilder<JavaClass> builder = fixtureMonkey.giveMeBuilder(JavaClass.class);
builder.set("$", new JavaClass(...));

2. Selecting a Direct Field

builder.set("field", "Hello World");

3. Selecting a Nested Field

builder.set("object.nestedField", "Nested Value");

4. Working with Collections

// Set the first item in the list
builder.set("list[0]", "First Item");

// Set ALL items in the list (wildcard)
builder.set("list[*]", "Same Value");

5. Working with Arrays

Very similar to lists:

builder.set("array[0]", "First Element");
builder.set("array[*]", "All Elements");

6. Complex Nested Paths

You can combine these patterns to go as deep as you need:

// nestedField of first object in list
builder.set("objectList[0].nestedField", "First Nested");

// nestedField of ALL objects in list
builder.set("objectList[*].nestedField", "All Nested");

Type-Safe Selection

Java: JavaGetter

If you prefer to avoid string-based expressions in Java, you can use type-safe getters:

// Direct field
builder.set(javaGetter(JavaClass::getField), "Hello World");

// Nested field
builder.set(
javaGetter(JavaClass::getObject).into(Nested::getNestedField),
"Nested Value"
);

// Collection elements
builder.set(javaGetter(JavaClass::getList).index(String.class, 0), "First");
builder.set(javaGetter(JavaClass::getList).allIndex(String.class), "All");

Kotlin: DSL Exp

Kotlin users can use property references for type-safe expressions:

// Direct field
builder.setExp(KotlinClass::field, "Hello World")

// Nested field
builder.setExp(KotlinClass::`object` into KotlinClass.Nested::nestedField, "Nested Value")

// Collection elements
builder.setExp(KotlinClass::objectList["0"] into KotlinClass.Nested::nestedField, "First")
builder.setExp(KotlinClass::objectList["*"] into KotlinClass.Nested::nestedField, "All")

For more details on Kotlin DSL Expressions, see the Kotlin DSL Exp page.

Common Beginner Questions

What happens if I try to access an out-of-bounds index?

If you try to access an element that doesn't exist (e.g., "list[5]" when the list only has 3 items), Fixture Monkey will simply ignore that setting. To catch these issues, you can enable Expression Strict Mode.

How do I handle maps?

While you can't directly access map elements with path expressions, you can use InnerSpec to customize maps.

Can I use multiple path expressions at once?

Yes! You can chain multiple .set() calls:

ArbitraryBuilder<JavaClass> builder = fixtureMonkey.giveMeBuilder(JavaClass.class)
.set("field", "Value 1")
.set("object.nestedField", "Value 2")
.set("list[*]", "Value 3");

Advanced Options

Expression Strict Mode

Enable this option to make Fixture Monkey validate all path expressions:

FixtureMonkey fixtureMonkey = FixtureMonkey.builder()
.setExpressionStrictMode(true)
.build();

With strict mode enabled, invalid paths will throw exceptions, helping you catch mistakes early.

Summary

Path expressions are a powerful feature of Fixture Monkey that let you:

  • Navigate to any part of your test object structure
  • Set specific values for testing different scenarios
  • Modify multiple related fields in one operation
  • Keep your test code clean and readable

Start with simple direct field access, then gradually explore collection access and nested properties as you grow comfortable with the syntax.