View on GitHub

Instancio Extension - Fixture Builder

instancio-fixture-builder usage documentation

Implementation example

POJO classes

Obviously we need some classes that contain some data. Classes can be composites.

Dummy

public class Dummy {
    private final String name, firstName;
    private final LocalDate birthDate;
    private final Integer reliabilityScore;
    private final ContactDetails contactDetails;

    // Constructors and getters omitted...
}

ContactDetails

public class ContactDetails {
    private final String phoneNumber;
    private final String mobileNumber;
    private final String email;

    // Constructors and getters omitted...
}

Fixture Classes

Instancio provides a possibility to instantiate classes easily. The FixtureBuilder improves this functionality by adding more fine grained control to how the values are being set. This is especially useful for big/complex datastructures and/or immutable state.

DummyFixtures

We only need to define a xxxFixtures class that is annotated with @GenerateFixtureBuilder. To be able to generate the fixture builder, we also require an Instancio Model to be defined. This model should be annotated with @InstancioModel so the annotation processor is able to detect it.

@GenerateFixtureBuilder(builderForType = Dummy.class, fixtureClass = DummyFixtures.class)
public class DummyFixtures {
    @InstancioModel
    static final Model<Dummy> DUMMY_MODEL = Instancio.of(Dummy.class)
            .generate(field(Person::getBirthDate), gen -> gen.temporal().localDate().past())
            .supply(field(Person::getContactDetails), ContactDetailsFixtures::contactDetails)
            .toModel();

    // This method is optional!
    public static DummyFixtureBuilder dummyFixtureBuilder() {
        return new DummyFixtureBuilder();
    }
}

When we have defined out DummyFixtures class, we can build or project. During this build, the DummyFixtureBuilder will be generated. The generated code can be found below.

NOTE: If you want your IntelliJ to generate the code, make sure annotation processing is enabled!

DummyFixtureBuilder (GENERATED)

@Generated("Generated by instancio-fixture-builder annotation processor on 2025-02-04T17:34:09.92189")
public class DummyFixtureBuilder extends AbstractFixtureBuilder<Dummy, DummyFixtureBuilder> {
    @Override
    public DummyFixtureBuilder self() {
        return this;
    }

    @Override
    public Dummy build() {
        return buildInternal(DUMMY_MODEL);
    }

    public static DummyFixtureBuilder fixtureBuilder() {
        return new DummyFixtureBuilder();
    }

    public static DummyFixtureBuilder toFixtureBuilder(final Dummy obj) {
        DummyFixtureBuilder builder = new DummyFixtureBuilder();
        builder.withContactDetails(obj.getContactDetails());
        builder.withBirthDate(obj.getBirthDate());
        builder.withName(obj.getName());
        builder.withReliabilityScore(obj.getReliabilityScore());
        builder.withFirstName(obj.getFirstName());
        return builder;
    }

    public DummyFixtureBuilder withFirstName(String firstName) {
        return set(Select.field(Dummy.class, "firstName"), firstName);
    }

    public DummyFixtureBuilder ignoreFirstName() {
        return withFirstName(null);
    }

    public DummyFixtureBuilder withName(String name) {
        return set(Select.field(Dummy.class, "name"), name);
    }

    public DummyFixtureBuilder ignoreName() {
        return withName(null);
    }

    public DummyFixtureBuilder withBirthDate(LocalDate birthDate) {
        return set(Select.field(Dummy.class, "birthDate"), birthDate);
    }

    public DummyFixtureBuilder ignoreBirthDate() {
        return withBirthDate(null);
    }

    public DummyFixtureBuilder withContactDetails(ContactDetails contactDetails) {
        return set(Select.field(Dummy.class, "contactDetails"), contactDetails);
    }

    public DummyFixtureBuilder ignoreContactDetails() {
        return withContactDetails(null);
    }

    public DummyFixtureBuilder withReliabilityScore(Integer reliabilityScore) {
        return set(Select.field(Dummy.class, "reliabilityScore"), reliabilityScore);
    }

    public DummyFixtureBuilder ignoreReliabilityScore() {
        return withReliabilityScore(null);
    }
}

Example Usage

This is how a complete person could be created using only the Fixture Builder:

Person person = PersonFixtures.fixtureBuilder()
                        .withName(name)
                        .withFirstName(firstName)
                        .withBirthDate(dateOfBirth)
                        .withReliabilityScore(reliabilityScore)
                        .withContactDetails(ContactDetailsFixtures.contactDetails())
                        .build();

You could also use the static factory method included in the PersonFixtureBuilder to obtain a new instance.

Person person = PersonFixtureBuilder.fixtureBuilder()
        .withName(name)
        .withFirstName(firstName)
        .withBirthDate(dateOfBirth)
        .withReliabilityScore(reliabilityScore)
        .withContactDetails(ContactDetailsFixtures.contactDetails())
        .build();

If you have an existing instance that you need to modify, use the toFixtureBuilder method which requires an instance as a parameter. The toFixtureBuilder method creates a new fixture builder which is populated with the field values of given instance. All field values can then be modified and/or ignored before creating a new instance. The original instance is not modified!

// The aPerson() method returns a fully populated Person instance
Person original = PersonFixtures.aPerson();

Person modifiedCopy = PersonFixtureBuilder.toFixtureBuilder(person)
        .withFirstName("a new name")
        .build();