{"id":25776497,"url":"https://github.com/easymodeling/easy-modeling","last_synced_at":"2026-01-11T16:57:35.957Z","repository":{"id":38150559,"uuid":"430498283","full_name":"easymodeling/easy-modeling","owner":"easymodeling","description":"EasyModeling is a Java annotation processor that generates randomly populated objects for test use.","archived":false,"fork":false,"pushed_at":"2023-03-10T03:00:54.000Z","size":911,"stargazers_count":41,"open_issues_count":9,"forks_count":3,"subscribers_count":4,"default_branch":"master","last_synced_at":"2023-11-18T16:33:03.023Z","etag":null,"topics":["java","object-mother","random","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/easymodeling.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/contributing.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-11-21T22:44:07.000Z","updated_at":"2023-10-31T12:10:28.000Z","dependencies_parsed_at":"2023-02-16T14:30:38.095Z","dependency_job_id":null,"html_url":"https://github.com/easymodeling/easy-modeling","commit_stats":null,"previous_names":[],"tags_count":9,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easymodeling%2Feasy-modeling","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easymodeling%2Feasy-modeling/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easymodeling%2Feasy-modeling/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easymodeling%2Feasy-modeling/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/easymodeling","download_url":"https://codeload.github.com/easymodeling/easy-modeling/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240987435,"owners_count":19889334,"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","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":["java","object-mother","random","testing"],"created_at":"2025-02-27T06:01:25.533Z","updated_at":"2026-01-11T16:57:35.945Z","avatar_url":"https://github.com/easymodeling.png","language":"Java","funding_links":[],"categories":["测试"],"sub_categories":[],"readme":"# EasyModeling\n\n[![version][release-badge]][release-link]\n[![maven][maven-badge]][search-maven]\n[![license][license-badge]][license-2.0]\n\n[![CI][ci-badge]][ci-link]\n[![Quality Gate Status][sonar-badge]][sonar-link]\n[![Coverage][coverage-badge]][coverage-link]\n\nA Java annotation processor that generates randomly populated objects for test use.\n\n[release-badge]: https://img.shields.io/github/v/release/easymodeling/easy-modeling?color=informational\u0026include_prereleases\u0026label=latest%20release\n\n[release-link]: https://github.com/easymodeling/easy-modeling/releases\n\n[maven-badge]: https://img.shields.io/maven-central/v/io.github.easymodeling/easy-modeling?color=green\n\n[license-badge]: https://img.shields.io/github/license/easymodeling/easy-modeling?color=yellow\n\n[ci-badge]: https://github.com/easymodeling/easy-modeling/actions/workflows/ci.yml/badge.svg?branch=master\n\n[ci-link]: https://github.com/easymodeling/easy-modeling/actions/workflows/ci.yml\n\n[sonar-badge]: https://sonarcloud.io/api/project_badges/measure?project=easymodeling_easy-modeling\u0026metric=alert_status\n\n[sonar-link]: https://sonarcloud.io/summary/new_code?id=easymodeling_easy-modeling\n\n[coverage-badge]: https://sonarcloud.io/api/project_badges/measure?project=easymodeling_easy-modeling\u0026metric=coverage\n\n[coverage-link]: https://sonarcloud.io/summary/overall?id=easymodeling_easy-modeling\n\n## What is EasyModeling?\n\nEasyModeling is a Java [annotation processor][java-atp-link] that generates randomly populated objects for test use. It\ncould save you from writing tedious code to prepare objects for tests, making your unit tests clearer and more readable.\nThe idea of EasyModeling comes from Martin Fowler's blog [ObjectMother][object-mother-link]. In addition to the concept\nof ObjectMother, EasyModeling also provides builders of your models so that you can easily customize generated objects\nfor different test scenarios.\n\n[java-atp-link]: https://docs.oracle.com/javase/6/docs/technotes/guides/apt/index.html\n\n[object-mother-link]: https://martinfowler.com/bliki/ObjectMother.html\n\n## What can EasyModeling do?\n\nEasyModeling provides a set of APIs to help you generate objects for your test, including:\n\n- An annotation `@Model` to tell EasyModeling for which classes you would like to generate objects.\n- An annotation `@Field` and many annotation attributes, which is however totally optional, to customize the generated\n  objects.\n- A `next()` method for each class returns randomly populated objects.\n- A `builder()` method for each class returns randomly populated builders of the objects.\n\n### Simple Example\n\nFor example, if you have a class `Employee` involved in your test so that you want to generate objects for it, you can\nfirstly have a modeler configuration like this:\n\n```java\n\n@Model(type = Employee.class)\npublic class Modelers {\n}\n```\n\nThen, EasyModeling will create a modeler named `EmployeeModeler` for you so that you can use the static `next()`\nmethod to generate objects:\n\n[//]: # (@formatter:off)\n```java\nEmployee employee = EmployeeModeler.next();\n```\n[//]: # (@formatter:on)\n\nFor a specific test scenario, let's say for a test caring employee's age and marital status, by using static `builder()`\nmethod, you have the chance to customize the generated objects:\n\n[//]: # (@formatter:off)\n```java\nEmployee employee = EmployeeModeler.builder().age(30).maritalStatus(SINGLE).build();\n```\n[//]: # (@formatter:on)\n\n## Why EasyModeling?\n\nEasyModeling starts with the factory pattern and the builder pattern. The main purpose of EasyModeling is to make unit\ntests clearer and more readable. Let's assume we have a unit test for `annualLeave()` method of the `LeaveCalculator`\nwhose responsibility is to calculate the *total days of annual leave* of an employee from their *length of service*\nat the company. The test could be written as follows:\n\n[//]: # (@formatter:off)\n```java\n@Test\nvoid should_get_28_days_for_employees_less_than_5_years_of_service() {\n\n    // given (mock up employee details)\n    Employee employee = new Employee(\n            23212,                             // id\n            \"John\",                            // first name\n            \"Smith\",                           // last name\n            LocalDate.of(1991, 1, 23),         // birthdate\n            MaritalStatus.SINGLE,              // marital status\n            Position.DEVELOPER,                // position\n            List.of(                           // dependents\n                    new Dependent(...),\n                    new Dependent(...)\n                    new Dependent(...)\n            ),\n            LocalDate.of(2017, 8, 9),          // date of joining    --\u003e (1)\n            ...\n        );\n\n    // when\n    int annualLeave = leaveCalculator.annualLeave(employee);      // --\u003e (2)\n\n    // then\n    assertEquals(annualLeave, 28);                                // --\u003e (3)\n}\n```\n[//]: # (@formatter:on)\n\nSeveral pain points could be encountered when writing unit tests like above.\n\n1. The only codes that describe the test scenario are the lines of `(1)`, `(2)` and `(3)`. Others are just helping mock\n   up the context, which could not help us understand the test. In most cases, it's usual for these unnecessary mock-up\n   codes to become extremely long.\n2. Moreover, most of the mock-up would make the test harder to read. Even in a reasonably scaled system, developers will\n   find they have to create hundreds of verbose mock-up codes like above, which makes our tests neither readable nor\n   maintainable.\n3. Even if the constructor in the mock-up part could be replaced by some techniques like Builder Pattern, it won't help\n   reduce the complexity. And it also does not make too much sense to either allow some parameters of the constructor as\n   nullable or create a builder for the `Employee` class, only for the convenience of the tests.\n4. Regarding the maintainability, imagine we somehow changed any part of the parameter list of the constructor\n   of `Employee` class, we would have to change all the tests as well.\n\n**With the power of EasyModeling**, these problems could be solved significantly:\n\n[//]: # (@formatter:off)\n```java\n@Test\nvoid should_get_28_days_for_employees_less_than_5_years_of_service() {\n\n    // given (mock up employee details)\n    Employee employee = EmployeeModeler.builder()\n                            .dateOfJoining(LocalDate.of(2017, 8, 9))\n                            .build();\n\n    // when\n    int annualLeave = leaveCalculator.annualLeave(employee);\n\n    // then\n    assertEquals(annualLeave, 28);\n}\n```\n[//]: # (@formatter:on)\n\n## Requirements\n\nJava 1.8 or later is required.\n\n## Using EasyModeling\n\nEasyModeling is available in [Maven Central][search-maven], so it's easy to ask build tools like Maven or Gradle to\nintegrate it into your projects.\n\n[search-maven]: https://search.maven.org/search?q=g:io.github.easymodeling\n\n### Gradle\n\nFor Gradle users, put the following into your build.gradle file:\n\n[//]: # (@formatter:off)\n```groovy\ndependencies {\n    ...\n    testImplementation 'io.github.easymodeling:easy-modeling:0.1.3'\n    testAnnotationProcessor 'io.github.easymodeling:easy-modeling-processor:0.1.3'\n    ...\n}\n```\n[//]: # (@formatter:on)\n\n### Maven\n\nFor Maven-based projects, add the following to your POM file:\n\n[//]: # (@formatter:off)\n```xml\n\u003cdependencies\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003eio.github.easymodeling\u003c/groupId\u003e\n        \u003cartifactId\u003eeasy-modeling\u003c/artifactId\u003e\n        \u003cversion\u003e0.1.3\u003c/version\u003e\n        \u003cscope\u003etest\u003c/scope\u003e\n    \u003c/dependency\u003e\n\u003c/dependencies\u003e\n...\n\u003cbuild\u003e\n\u003cplugins\u003e\n    \u003cplugin\u003e\n        \u003cgroupId\u003eorg.apache.maven.plugins\u003c/groupId\u003e\n        \u003cartifactId\u003emaven-compiler-plugin\u003c/artifactId\u003e\n        \u003cversion\u003e3.8.1\u003c/version\u003e\n        \u003cconfiguration\u003e\n            \u003csource\u003e1.8\u003c/source\u003e\n            \u003ctarget\u003e1.8\u003c/target\u003e\n            \u003cannotationProcessorPaths\u003e\n                \u003cpath\u003e\n                    \u003cgroupId\u003eio.github.easymodeling\u003c/groupId\u003e\n                    \u003cartifactId\u003eeasy-modeling-processor\u003c/artifactId\u003e\n                    \u003cversion\u003e0.1.3\u003c/version\u003e\n                \u003c/path\u003e\n            \u003c/annotationProcessorPaths\u003e\n        \u003c/configuration\u003e\n    \u003c/plugin\u003e\n\u003c/plugins\u003e\n\u003c/build\u003e\n...\n```\n[//]: # (@formatter:on)\n\n### Note\n\nPlease be aware that EasyModeling is designed for test use, so think twice before using it in production. Using\nEasyModeling in production will introduce a lot of side effects, such as:\n\n- Security risks: Since EasyModeling generates randoms by using java.util.Random, which is not secure enough compared to\n  more advanced random generators.\n- Performance problem: EasyModeling is not optimized for performance. It generates objects by using reflection to\n  achieve the convenience and simplicity of writing tests, regardless of the runtime performance.\n- NPE risk: EasyModeling won't promise to populate all fields of the generated objects, although it always tries its\n  best to do so. It's possible that some fields are not populated, which may cause NPE.\n\n## Next Steps\n\nSome next steps are in consideration to improve EasyModeling:\n\n- Support some annotations from [Bean Validation 2.0][bean-validation-2.0] as the customizations of value ranges for\n  generated objects.\n- Groovy support.\n- Support more widely used data types as basic types of objects population.\n\n**Please feel free to [create an issues][raise-issues] if you have any more exciting ideas.**\n\n[bean-validation-2.0]: https://beanvalidation.org/2.0/spec/\n\n[raise-issues]: https://github.com/easymodeling/easy-modeling/issues/new?template=feature_request.yml\n\n## License\n\nEasyModeling is Open Source software licensed under the [APACHE LICENSE, VERSION 2.0][license-2.0].\n\n[license-2.0]: https://www.apache.org/licenses/LICENSE-2.0.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feasymodeling%2Feasy-modeling","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feasymodeling%2Feasy-modeling","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feasymodeling%2Feasy-modeling/lists"}