This page is generated from the following source files:
Fixture Monkey is a Java-based property-based testing library designed to generate arbitrary test fixtures with minimal boilerplate. The architecture follows a layered design with clear separation between API contracts, core implementation, and runtime engine components.
The system is organized into four primary layers: the public API layer (fixture-monkey-api), the core implementation layer (fixture-monkey), the runtime engine (fixture-monkey-engine), and integration modules for various frameworks. This layered approach enables extensibility while maintaining backward compatibility.
正在加载图表渲染器...
Key Architectural Points:
Layered Isolation: The API layer (fixture-monkey-api/build.gradle.kts:1-57) exposes only public interfaces, while the engine layer (fixture-monkey-engine/build.gradle.kts:1-14) handles jqwik integration as a runtime dependency.
Builder Pattern Entry: All configuration flows through FixtureMonkeyBuilder (fixture-monkey/src/main/java/com/navercorp/fixturemonkey/FixtureMonkeyBuilder.java:90-142), which constructs immutable FixtureMonkey instances with customized property generators and manipulators.
Tree-Based Object Model: The ObjectTree (fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/ObjectTree.java:51-68) represents the hierarchical structure of generated objects, enabling manipulation at any node level.
Resolution Pipeline: ArbitraryResolver (fixture-monkey/src/main/java/com/navercorp/fixturemonkey/resolver/ArbitraryResolver.java:716-868) implements a dual-path strategy with fast-path optimization for simple cases and full-path handling for complex scenarios.
Multi-Release JAR Support: Both API modules support Java 8 baseline with Java 17 enhancements (fixture-monkey-api/build.gradle.kts:7-11), enabling modern JVM optimizations while maintaining broad compatibility.
The FixtureMonkey class serves as the main entry point for fixture generation. It provides type-safe methods to create ArbitraryBuilder instances that generate test data.
java1// Entry point creation 2FixtureMonkey fixtureMonkey = FixtureMonkey.create(); 3 4// Type-safe builder acquisition 5ArbitraryBuilder<String> builder = fixtureMonkey.giveMeBuilder(String.class);
The core API methods include:
| Method | Purpose | Return Type |
|---|---|---|
create() | Factory method for default instance | FixtureMonkey |
giveMeBuilder(Class<T>) | Type-safe builder for raw types | ArbitraryBuilder<T> |
giveMeBuilder(TypeReference<T>) | Type-safe builder for generic types | ArbitraryBuilder<T> |
Implementation Details:
The giveMeBuilder method creates a DefaultArbitraryBuilder with a complete resolution context:
Root Property Creation: Wraps the requested type in a TreeRootProperty (fixture-monkey/src/main/java/com/navercorp/fixturemonkey/FixtureMonkey.java:145-152)
Context Matching: Filters registered arbitrary builders to find matching contexts for the requested type (fixture-monkey/src/main/java/com/navercorp/fixturemonkey/FixtureMonkey.java:154-165)
Resolver Instantiation: Creates an ArbitraryResolver with manipulator optimizer, factory, and caches (fixture-monkey/src/main/java/com/navercorp/fixturemonkey/FixtureMonkey.java:169-178)
The builder pattern enables extensive customization through a fluent API. Key configuration categories include:
Property Generators:
pushPropertyGenerator(MatcherOperator<PropertyGenerator>) - Generic property generationpushAssignableTypePropertyGenerator(Class<?>, PropertyGenerator) - Type hierarchy matchingpushExactTypePropertyGenerator(Class<?>, PropertyGenerator) - Exact type matchingObject Property Generators:
defaultObjectPropertyGenerator(ObjectPropertyGenerator) - Default behaviorpushAssignableTypeObjectPropertyGenerator(Class<?>, ObjectPropertyGenerator) - Polymorphic handlingpushExactTypeObjectPropertyGenerator(Class<?>, ObjectPropertyGenerator) - Precise controlThe builder maintains a FixtureMonkeyOptionsBuilder internally that accumulates all configuration before building the final FixtureMonkey instance (fixture-monkey/src/main/java/com/navercorp/fixturemonkey/FixtureMonkeyBuilder.java:91-109).
The ObjectTree class represents generated objects as a tree of ObjectNode instances. This structure enables:
正在加载图表渲染器...
Core Operations:
The ObjectTree provides two fundamental operations:
Manipulation (fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/ObjectTree.java:56-63):
NodeResolverNodeManipulator to each resolved nodeGeneration (fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/ObjectTree.java:65-67):
generateFixtureContextCombinableArbitrary for lazy evaluationThe MetadataCollector traverses the entire object tree to gather structural information:
Collection Process (fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/MetadataCollector.java:50-61):
Data Structures:
nodesByProperty: Map<Property, List<ObjectNode>> - Property-to-nodes mappingannotations: Set<Annotation> - All annotations in the treeThe recursive collection method (fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/MetadataCollector.java:63-79) extracts annotations from each node's property and merges nodes into the property map using stream concatenation.
The ArbitraryResolver implements a sophisticated dual-path strategy to balance performance and functionality:
正在加载图表渲染器...
Fast Path Conditions (fixture-monkey/src/main/java/com/navercorp/fixturemonkey/resolver/ArbitraryResolver.java:729-740):
The fast path activates when:
hasRegisteredBuilders == falsehasStandbyContexts == falseThis skips:
inferPossibleProperties computationcollectRelevantTypes traversalFull Path Processing (fixture-monkey/src/main/java/com/navercorp/fixturemonkey/resolver/ArbitraryResolver.java:829-868):
When registered builders exist, the full path:
inferPossibleProperties with cycle detectionThe ObjectBuilder<T> interface serves as an internal marker in the API layer (fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/ObjectBuilder.java:24-32):
@API(since = "1.1.0", status = Status.INTERNAL)The node predicate system enables flexible tree traversal through a composable interface hierarchy:
正在加载图表渲染器...
NextNodePredicate Interface (fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/NextNodePredicate.java:28-30):
java1public interface NextNodePredicate extends TraverseNodePredicate { 2 boolean test(ObjectProperty currentObjectProperty); 3}
This interface extends TraverseNodePredicate and adds the test method that accepts ObjectProperty for evaluation.
NodeTypePredicate provides type matching with two modes:
| Mode | Constructor | Behavior |
|---|---|---|
| Exact | NodeTypePredicate(Class<?>) | Requires exact type match |
| Assignable | NodeTypePredicate(Class<?>, false) | Allows subtype assignment |
Implementation (fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/NodeTypePredicate.java:51-59):
java1@Override 2public boolean test(ObjectProperty currentObjectProperty) { 3 Class<?> actualType = Types.getActualType(currentObjectProperty.getProperty().getType()); 4 if (exact) { 5 return type == actualType; 6 } 7 return type.isAssignableFrom(actualType); 8}
The predicate extracts the actual type using Types.getActualType() and performs either identity comparison (==) for exact mode or isAssignableFrom for polymorphic matching.
PropertyPredicate performs exact property matching:
Implementation (fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/PropertyPredicate.java:35-39):
java1@Override 2public boolean test(ObjectProperty currentObjectProperty) { 3 return property.equals(currentObjectProperty.getProperty()); 4}
This predicate uses equals comparison on the Property object, enabling precise node selection based on property identity.
NodeKeyPredicate detects map key elements:
Implementation (fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/NodeKeyPredicate.java:29-36):
java1@Override 2public boolean test(ObjectProperty currentObjectProperty) { 3 Property property = currentObjectProperty.getProperty(); 4 return property instanceof MapKeyElementProperty; 5}
This specialized predicate checks if the property is an instance of MapKeyElementProperty, enabling targeted manipulation of map keys during fixture generation.
The project follows a modular architecture with clear dependency boundaries:
正在加载图表渲染器...
Module Responsibilities:
| Module | Purpose | Key Dependencies |
|---|---|---|
fixture-monkey-api | Public interfaces, type system | object-farm-api, jqwik-api |
object-farm-api | Core abstractions | None (standalone) |
fixture-monkey | Main implementation | fixture-monkey-api, fixture-monkey-engine |
fixture-monkey-engine | jqwik engine integration | jqwik-engine |
fixture-monkey-kotlin | Kotlin extensions | fixture-monkey, kotlin-reflect |
fixture-monkey-kotest | Kotest property testing | fixture-monkey-kotlin, kotest-property-jvm |
The main fixture-monkey module (fixture-monkey/build.gradle.kts:1-20) declares:
kotlin1dependencies { 2 runtimeOnly(projects.fixtureMonkeyEngine) 3 api(projects.fixtureMonkeyApi) 4 api(libs.slf4j.api) 5 api(libs.jqwik) 6 api(libs.rgxgen) 7 api(libs.generex) 8}
Key Points:
fixtureMonkeyEngine is a runtime dependency (not exposed to consumers)jqwik is exposed via api for property-based testing supportrgxgen, generex) are exposed for string generationThe fixture-monkey-api module (fixture-monkey-api/build.gradle.kts:28-48) uses compileOnly for jqwik dependencies:
kotlin1dependencies { 2 api(libs.apiguardian.api) 3 api(projects.objectFarmApi) 4 5 compileOnly(libs.jqwik.engine) 6 compileOnly(libs.jqwik.api) 7 compileOnly(libs.jqwik.web) 8 compileOnly(libs.jqwik.time) 9 compileOnly(libs.rgxgen) 10 compileOnly(libs.generex) 11}
This ensures the API module remains lightweight while providing compatibility with jqwik features.
Both API modules support multi-release JARs for Java 8 baseline with Java 17 enhancements:
Configuration (fixture-monkey-api/build.gradle.kts:7-26):
kotlin1val multiReleaseVersions = intArrayOf(17) 2 3multiRelease { 4 targetVersions(8, *multiReleaseVersions) 5} 6 7multiReleaseVersions.forEach { releaseVersion -> 8 configurations.filter { it.name.startsWith("java$releaseVersion") } 9 .forEach { configuration -> 10 configuration.extendsFrom( 11 configurations.getByName(defaultVersionConfigurationName) 12 ) 13 } 14}
This enables:
正在加载图表渲染器...
Flow Explanation:
Entry Point: Client invokes giveMeBuilder with target type (fixture-monkey/src/main/java/com/navercorp/fixturemonkey/FixtureMonkey.java:145-152)
Context Setup: System creates TreeRootProperty and filters registered builders for matching contexts
Resolver Creation: DefaultArbitraryBuilder receives a new ArbitraryResolver instance with all required components
Path Selection: Resolver checks fast path conditions (fixture-monkey/src/main/java/com/navercorp/fixturemonkey/resolver/ArbitraryResolver.java:729-740)
Generation: Selected path generates CombinableArbitrary through the engine
Tree Construction: ObjectTree is built with metadata from MetadataCollector
Manipulation: Any pending manipulators are applied to resolved nodes
1. Builder Pattern for Configuration
The FixtureMonkeyBuilder implements a fluent builder pattern for configuration. This decision enables:
FixtureMonkey instances after constructionTrade-off: Configuration changes require creating a new FixtureMonkey instance, which may have initialization overhead.
2. Dual-Path Resolution Strategy
The fast path/full path split in ArbitraryResolver optimizes for the common case (no registered builders) while maintaining full functionality for complex scenarios.
Evidence: The fast path check at fixture-monkey/src/main/java/com/navercorp/fixturemonkey/resolver/ArbitraryResolver.java:729-740 explicitly skips "register-related preparation" for performance.
3. Tree-Based Object Model
The ObjectTree representation enables:
CombinableArbitraryTrade-off: Tree construction has upfront cost, but enables efficient manipulation without regenerating entire structures.
4. Multi-Release JAR Architecture
Supporting both Java 8 and Java 17 enables:
Evidence: Multi-release configuration at fixture-monkey-api/build.gradle.kts:9-11 explicitly targets versions 8 and 17.
5. Predicate-Based Node Selection
The NextNodePredicate hierarchy enables composable node matching strategies:
Trade-off: Predicate evaluation adds overhead during tree traversal, but enables flexible and expressive node selection.
6. Separation of API and Implementation
The fixture-monkey-api module contains only interfaces and contracts, while fixture-monkey contains implementations. This enables:
7. Runtime Engine Dependency
The fixture-monkey-engine module is declared as runtimeOnly in the core module, meaning:
| Technology | Purpose | Selection Rationale | Alternatives Considered |
|---|---|---|---|
| jqwik | Property-based testing engine | Native Java support, mature API, active development | QuickCheck, junit-quickcheck |
| Kotlin | Extension language | Null safety, extension functions, Java interop | Groovy, Scala |
| Kotest | Kotlin testing framework | Idiomatic Kotlin DSL, property testing support | Spek, Kluent |
| Jackson | JSON serialization | Performance, flexibility, wide adoption | Gson, Moshi |
| Gradle | Build system | Kotlin DSL, multi-module support, incremental builds | Maven, Bazel |
| Multi-Release JAR | Java version compatibility | Single artifact for Java 8-17, no deployment complexity | Separate artifacts, shaded JARs |
| Regex generators (rgxgen, generex) | String pattern generation | Xeger-compatible, Unicode support | Custom implementation |
| SpotBugs | Static analysis | Bytecode analysis, FindBugs successor | PMD, Checkstyle |
| Checker Framework | Type checking | Nullness checking, incremental adoption | NullAway, Error Prone |
The project defines custom Gradle plugins in buildSrc (buildSrc/build.gradle.kts:12-35):
| Plugin ID | Purpose |
|---|---|
com.navercorp.fixturemonkey.gradle.plugin.optional-dependencies | Optional dependency handling |
com.navercorp.fixturemonkey.gradle.plugin.java-conventions | Java toolchain and compilation settings |
com.navercorp.fixturemonkey.gradle.plugin.maven-publish-conventions | Maven Central publishing configuration |
com.navercorp.fixturemonkey.gradle.plugin.object-farm-maven-publish-conventions | Object Farm specific publishing |
com.navercorp.fixturemonkey.gradle.plugin.checker-framework-conventions | Type checking integration |
All subprojects use Java 8 toolchain with Javadoc and sources JARs (build.gradle.kts:32-36):
kotlin1java { 2 toolchain { languageVersion = JavaLanguageVersion.of(8) } 3 withJavadocJar() 4 withSourcesJar() 5}
Test tasks use jqwik engine for property-based testing (build.gradle.kts:56-62):
kotlin1if (!name.endsWith("tests")) { 2 tasks.withType<Test> { 3 useJUnitPlatform { 4 includeEngines("jqwik") 5 } 6 } 7}
This configuration excludes test utility modules from jqwik execution, ensuring only actual test modules run property-based tests.