{"id":31727143,"url":"https://github.com/romann-broque/java-fixture-generator","last_synced_at":"2025-10-09T06:18:41.665Z","repository":{"id":317226675,"uuid":"1047998754","full_name":"romann-broque/java-fixture-generator","owner":"romann-broque","description":"Compile-time fixture builders for Java — annotate a DataSet, get a fluent *Fixture* API.","archived":false,"fork":false,"pushed_at":"2025-09-29T16:07:43.000Z","size":79,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-29T17:37:36.268Z","etag":null,"topics":["annotation-processor","builder-design-pattern","builder-pattern","code-generation","data-test","fixtures","gradle","java","maven-central","spring-boot","test-automation","test-fixture","test-fixtures","testing"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/romann-broque.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":"NOTICE","maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-08-31T17:37:58.000Z","updated_at":"2025-09-29T16:07:47.000Z","dependencies_parsed_at":"2025-09-29T17:37:44.561Z","dependency_job_id":null,"html_url":"https://github.com/romann-broque/java-fixture-generator","commit_stats":null,"previous_names":["romann-broque/java-fixture-generator"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/romann-broque/java-fixture-generator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/romann-broque%2Fjava-fixture-generator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/romann-broque%2Fjava-fixture-generator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/romann-broque%2Fjava-fixture-generator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/romann-broque%2Fjava-fixture-generator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/romann-broque","download_url":"https://codeload.github.com/romann-broque/java-fixture-generator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/romann-broque%2Fjava-fixture-generator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279000852,"owners_count":26082950,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-09T02:00:07.460Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["annotation-processor","builder-design-pattern","builder-pattern","code-generation","data-test","fixtures","gradle","java","maven-central","spring-boot","test-automation","test-fixture","test-fixtures","testing"],"created_at":"2025-10-09T06:18:36.701Z","updated_at":"2025-10-09T06:18:41.660Z","avatar_url":"https://github.com/romann-broque.png","language":"Java","readme":"# Java Fixture Generator\n\n[![Maven Central](https://img.shields.io/maven-central/v/io.github.romann-broque/fixture-annotations.svg?label=maven%20central)](https://central.sonatype.com/artifact/io.github.romann-broque/fixture-annotations)\n[![Javadoc](https://javadoc.io/badge2/io.github.romann-broque/fixture-annotations/javadoc.svg)](https://javadoc.io/doc/io.github.romann-broque/fixture-annotations)\n[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](./LICENSE)\n\n✋ Stop wiring test objects by hand. \u003c/br\u003e ✨ Fixtures are now writing themselves. \u003c/br\u003e\n\nAnnotate a `DataSet` and let the compiler produce a fluent `*Fixture` API (`buildDefault()`, `with…`, `without…`) so you can express test intent in a couple of lines.\n\n- **`fixture-annotations`** — 🏷️ public annotations to mark your DataSet classes\n- **`fixture-processor`** — ⚙️ the annotation processor that generates fixture builders\n\n\u003e 🔧 Java 21+, Gradle 8+, Maven 3.9+. Works with plain JUnit and Spring Boot.\n\n---\n\n## 📦 Installation\n\n### Gradle (Java)\n\n```groovy\nrepositories { mavenCentral() }\n\n// Generate fixtures for application sources (src/main/java)\ndependencies {\n  implementation \"io.github.romann-broque:fixture-annotations:x.y.z\"\n  annotationProcessor \"io.github.romann-broque:fixture-processor:x.y.z\"\n}\n\n// Generate fixtures for tests (src/test/java)\ndependencies {\n  testImplementation \"io.github.romann-broque:fixture-annotations:x.y.z\"\n  testAnnotationProcessor \"io.github.romann-broque:fixture-processor:x.y.z\"\n}\n\n```\n---\n\n## 🧪 Usage example\n\nAssuming you have a `Customer` model you want to test:\n\n```java\npackage org.example.testfixtures.models;\n\nimport java.time.LocalDate;\nimport java.util.Objects;\nimport lombok.AccessLevel;\nimport lombok.AllArgsConstructor;\nimport lombok.Getter;\nimport org.example.testfixtures.exceptions.CustomerException;\n\n@Getter\n@AllArgsConstructor(access = AccessLevel.PRIVATE)\npublic class Customer {\n  private String firstName;\n  private String lastName;\n  private String email;\n  private LocalDate birthDate;\n  private String phoneNumber;\n  private String address;\n\n  public static Customer create(final String firstName,\n                                final String lastName,\n                                final String email,\n                                final LocalDate birthDate,\n                                final String phoneNumber,\n                                final String address) {\n    try {\n      Objects.requireNonNull(firstName, \"First name is required\");\n      Objects.requireNonNull(lastName, \"Last name is required\");\n      Objects.requireNonNull(email, \"Email is required\");\n      Objects.requireNonNull(birthDate, \"Birth date is required\");\n      return new Customer(firstName, lastName, email, birthDate, phoneNumber, address);\n    } catch (final NullPointerException e) {\n      throw new CustomerException(\"Failed to create Customer: \" + e.getMessage());\n    }\n  }\n\n  public boolean isAdult() {\n    return LocalDate.now().isAfter(birthDate.plusYears(18));\n  }\n}\n```\n\n### 🧩 Using the generated Fixture\n\nYou can create a `DataSet` class annotated with `@Fixture`.\nThe annotation processor generates a fluent, chainable builder:\n\n- ⚡ `buildDefault()` → immediately builds the entity using **all default values** from your `DataModel`.\n- 🧱 `defaultFixture()` → returns a **mutable builder** pre-filled with the `DataModel` defaults; call `build()` to create the entity. \n- 🎛️ `withModel(model)` → same as *defaultFixture()*, but seeded with the given DataModel.\n- 🛠️ `with\u003cField\u003e(value)` → overrides a single field on the underlying `DataModel`.\n- 🚫 `without\u003cField\u003e()` → convenience for `with\u003cField\u003e(null)` (sets the model field to `null`).\n- 🔗 All `with…`/`without…` methods are **chainable**; **last call wins**.\n\n\u003e 🗂️ Generated sources live under  \n\u003e `build/generated/sources/annotationProcessor/java/(main|test)/...`\n\n### ✨ Minimal example\n\n```java\n@GenerateFixture(entityClass = Customer.class, dataModelClass = CustomerDataSet.DataModel.class)\npublic class CustomerDataSet {\n  public static Customer build(DataModel m) {\n    return Customer.create(m.firstName, m.lastName, m.email, m.birthDate, m.phoneNumber, m.address);\n  }\n  public static class DataModel {\n    public String firstName = \"John\";\n    public String lastName  = \"Smith\";\n    public String email     = \"john.smith@corporation.com\";\n    public LocalDate birthDate = LocalDate.of(1990, 1, 1);\n    public String phoneNumber = \"+1234567890\";\n    public String address     = \"123 Main St, Anytown, USA\";\n  }\n}\n```\n#### ✅ Build with defaults\n\n```java\n// Exactly equivalent:\nCustomer a = CustomerFixture.buildDefault();\nCustomer b = CustomerFixture.defaultFixture().build();\n```\n\n#### ✏️ Override selected fields (with…) and chain\n\n```java\nCustomer c = CustomerFixture\n    .defaultFixture()\n    .withFirstName(\"Alice\")\n    .withLastName(\"Doe\")\n    .withPhoneNumber(\"+33 6 12 34 56 78\")\n    .build();\n```\n\n#### 🚫 Explicitly null a field (without…)\n\n```java\nCustomer d = CustomerFixture\n.defaultFixture()\n.withoutAddress()     // same as .withAddress(null)\n.build();\n```\nIf your factory/constructor enforces non-nulls (e.g., email is required), you can assert failures:\n```java\nassertThrows(CustomerException.class, () -\u003e\n    CustomerFixture.defaultFixture().withoutEmail().build()\n);\n```\n#### 🔀 Combine with… and without… freely (order doesn’t matter; last wins)\n\n```java\nCustomer e = CustomerFixture\n    .defaultFixture()\n    .withoutPhoneNumber()\n    .withBirthDate(LocalDate.now().minusYears(25))\n    .withoutAddress()\n    .withAddress(\"42 Rue de la Paix\")     // last setter wins → address is NOT null\n    .build();\n```\n\n#### 🎛️ Using a custom DataModel (presets)\n\nBeyond the default DataModel, you can supply a custom model to bootstrap your fixture with a specific preset (e.g., a teen customer, a corporate email, etc.).\nJust declare another DataModel variant and pass it via withModel(...).\n\n#####  Declaration\n\n```java\n@GenerateFixture(entityClass = Customer.class, dataModelClass = CustomerDataSet.DataModel.class)\npublic class CustomerDataSet {\n  public static Customer build(DataModel m) {\n    ...\n  }\n  public static class DataModel {\n    ...\n  }\n\n  /** 👇 Preset: under-18 customer (non-adult) */\n  public static class TeenCustomer extends DataModel {\n    public TeenCustomer() {\n      this.birthDate = LocalDate.now().minusYears(16);\n    }\n  }\n}\n```\n\n#####  Usage\n\n```java\nCustomer teen = CustomerFixture\n    .withModel(new CustomerDataSet.TeenCustomer())\n    .build();\n```\n\n#### 🔁 Parameterized tests stay clean and intention-revealing\n\n```java\n@ParameterizedTest\n@MethodSource(\"validAdultBirthDateProvider\")\nvoid qualifies_as_adult(LocalDate birthDate) {\n  Customer customer = CustomerFixture.defaultFixture().withBirthDate(birthDate).build();\n  assertTrue(customer.isAdult());\n}\n\nstatic Stream\u003cArguments\u003e validAdultBirthDateProvider() {\n  return Stream.of(\n      Arguments.of(LocalDate.now().minusYears(18).minusDays(1)),\n      Arguments.of(LocalDate.now().minusYears(25))\n  );\n}\n```\n\n### 🎉 That's it!\nOnce you created the `DataSet` class, the fixture will be generated at compile time.\nSo build your project, and start using the generated `*Fixture` class in your tests.\n\n---\n\n## 📚 Additional resources\n\n- https://refactoring.guru/design-patterns/builder\n- https://ardalis.com/improve-tests-with-the-builder-pattern-for-test-data/\n\n## 🙏 Thanks\n\nSpecial thanks to [Frédéric Foissey](https://github.com/ffoissey) for the original idea and initial implementation of these modules. The current codebase extends and maintains his initial work.\n\n## 🤝 Contributing\n\nIssues and PRs are welcome. Please include a minimal reproduction for bugs.\n\n## 📄 Notices \u0026 License\n\n- License: [Apache-2.0](./LICENSE)\n- Notices: see [NOTICE](./NOTICE)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fromann-broque%2Fjava-fixture-generator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fromann-broque%2Fjava-fixture-generator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fromann-broque%2Fjava-fixture-generator/lists"}