Skip to main content
Version: v1.1.x

FAQ

How do I get started with Fixture Monkey?

Fixture Monkey provides a simple way to create test objects with random values. Here's how to get started:

// Create a FixtureMonkey instance
FixtureMonkey fixtureMonkey = FixtureMonkey.create();

// Generate a random object
Person person = fixtureMonkey.giveMeOne(Person.class);

How do I add Fixture Monkey to my project?

You can easily add Fixture Monkey to your Maven or Gradle project:

implementation("com.navercorp.fixturemonkey:fixture-monkey:1.1.x")

How do I specify values for certain fields while keeping others random?

You can use the set() method to specify values for specific fields:

Person person = fixtureMonkey.giveMeBuilder(Person.class)
.set("name", "John Doe")
.set("age", 25)
.sample();

How do I control the size of collections like List, Set or Map?

You can control the size of collections using the size() method:

Person person = fixtureMonkey.giveMeBuilder(Person.class)
.size("friends", 5) // Sets the size of the friends list to 5
.sample();

// Setting a range for size
Product product = fixtureMonkey.giveMeBuilder(Product.class)
.size("tags", 2, 5) // The tags list will have between 2 and 5 elements
.sample();

How do I handle null values?

You can control null probability using the nullInject option:

// Create a FixtureMonkey with no null values
FixtureMonkey fixtureMonkey = FixtureMonkey.builder()
.nullInject(0.0) // Set null probability to 0
.build();

// Create a FixtureMonkey with 50% null probability
FixtureMonkey fixtureMonkey = FixtureMonkey.builder()
.nullInject(0.5) // Set null probability to 50%
.build();

// Set a specific field to null
Person person = fixtureMonkey.giveMeBuilder(Person.class)
.set("address", null)
.sample();

How do I make my tests reproducible?

You can use a fixed seed to generate the same data across test runs:

// Create a FixtureMonkey with a fixed seed
FixtureMonkey fixtureMonkey = FixtureMonkey.builder()
.seed(123L)
.build();

With JUnit, you can also use the @Seed annotation:

@Test
@Seed(123L)
void testWithSeed() {
Person person = fixtureMonkey.giveMeOne(Person.class);
// The same Person will be generated every time
}

How do I ensure generated objects satisfy certain conditions?

You can use setPostCondition() to filter generated objects that don't meet your criteria:

// Ensure the person is an adult
Person adult = fixtureMonkey.giveMeBuilder(Person.class)
.setPostCondition(person -> person.getAge() >= 18)
.sample();

// Ensure a specific field meets a condition
Product product = fixtureMonkey.giveMeBuilder(Product.class)
.setPostCondition("price", Double.class, price -> price > 0 && price < 1000)
.sample();

How can I exclude certain values from being generated?

You can use set() with a filter to exclude certain values:

Product product = sut.giveMeBuilder(Product.class)
.set("productType", ArbitraryUtils.toCombinableArbitrary(Arbitraries.of(ProductType)).filter(it -> it != CLOTHING && it != ELECTRONICS))
.sample();

Or you can use setPostCondition() which works like a filter:

Product product = sut.giveMeBuilder(Product.class)
.setPostCondition("productType", ProductType.class, it -> it != CLOTHING && it != ELECTRONICS)
.sample();

Please note that using setPostCondition() can incur higher costs for narrow conditions because it filters after the Product instance has been created. In such cases, it's recommended to use set() instead.

How do I handle nested objects?

Fixture Monkey automatically generates nested objects. You can customize them using a property path:

Order order = fixtureMonkey.giveMeBuilder(Order.class)
.set("customer.name", "John Doe")
.set("customer.address.city", "New York")
.size("items", 3)
.set("items[0].productName", "Laptop")
.sample();

One of my fields depends on the value of another field. How can I customize my fixture?

The thenApply() method comes in handy when you need to customize a field that relies on another field:

Money money = fixtureMonkey.giveMeBuilder(Money.class)
.set("currency", Currency.getInstance("USD"))
.thenApply((m, builder) ->
builder.set("amount", m.getCurrency().equals(Currency.getInstance("USD")) ? 100.0 : 120.0))
.sample();

For more information, check the thenApply() section.

How can I limit the range of characters for my generated Strings?

Related - How can I constrain the range of my generated Instant values?

If you want each generated primitive type to adhere to specific constraints, you can use the javaTypeArbitaryGenerator and javaTimeTypeArbitraryGenerator options.

// Configure String generation with specific character ranges
FixtureMonkey fixtureMonkey = FixtureMonkey.builder()
.javaTypeArbitraryGenerator(new JavaTypeArbitraryGenerator() {
@Override
public StringArbitrary strings() {
return Arbitraries.strings().alpha().ofLength(5, 10);
}
})
.build();

// Configure time generation with specific ranges
FixtureMonkey fixtureMonkey = FixtureMonkey.builder()
.javaTimeTypeArbitraryGenerator(new JavaTimeTypeArbitraryGenerator() {
@Override
public Arbitrary<Instant> instant() {
Instant start = Instant.parse("2023-01-01T00:00:00Z");
Instant end = Instant.parse("2023-12-31T23:59:59Z");
return Arbitraries.instants().between(start, end);
}
})
.build();

Throws an exception when generating a certain type

If you encounter exceptions when generating certain types, try using PriorityConstructorArbitraryIntrospector:

FixtureMonkey fixtureMonkey = FixtureMonkey.builder()
.pushExactTypeArbitraryIntrospector(ProblematicType.class, PriorityConstructorArbitraryIntrospector.INSTANCE)
.build();

// Now generation should work
ProblematicType instance = fixtureMonkey.giveMeOne(ProblematicType.class);

If it does not work, please try to make your own ArbitraryIntrospector or create an issue on GitHub and ask for help.