{"id":17195955,"url":"https://github.com/npryce/make-it-easy","last_synced_at":"2025-08-20T22:31:36.201Z","repository":{"id":28706488,"uuid":"32227023","full_name":"npryce/make-it-easy","owner":"npryce","description":"A tiny framework that makes it easy to write Test Data Builders in Java","archived":false,"fork":false,"pushed_at":"2025-04-05T14:30:35.000Z","size":560,"stargazers_count":159,"open_issues_count":0,"forks_count":7,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-08-15T05:02:01.300Z","etag":null,"topics":[],"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/npryce.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2015-03-14T18:54:40.000Z","updated_at":"2025-08-13T11:13:05.000Z","dependencies_parsed_at":"2025-05-08T19:41:17.044Z","dependency_job_id":"b351d49f-0da1-4604-b04c-340f62af835a","html_url":"https://github.com/npryce/make-it-easy","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/npryce/make-it-easy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/npryce%2Fmake-it-easy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/npryce%2Fmake-it-easy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/npryce%2Fmake-it-easy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/npryce%2Fmake-it-easy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/npryce","download_url":"https://codeload.github.com/npryce/make-it-easy/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/npryce%2Fmake-it-easy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270567029,"owners_count":24608078,"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-08-15T02:00:12.559Z","response_time":110,"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":[],"created_at":"2024-10-15T01:51:57.668Z","updated_at":"2025-08-20T22:31:35.843Z","avatar_url":"https://github.com/npryce.png","language":"Java","funding_links":[],"categories":["测试"],"sub_categories":[],"readme":"A tiny framework that makes it easy to write Test Data Builders in Java\n\n[![Build Status](https://travis-ci.org/npryce/make-it-easy.svg?branch=master)](https://travis-ci.org/npryce/make-it-easy)\n\nTest Data Builders are described in the book [Growing Object-Oriented Software, Guided by Tests](http://www.growing-object-oriented-software.com) by [Steve Freeman](http://www.m3p.co.uk) and [Nat Pryce](http://www.natpryce.com).  This library lets you write Test Data Builders with much less duplication and boilerplate code than the approach described in the book.\n\n## Download ##\n\nYou can download from Maven Central with the artifact coordinates:\n\n    com.natpryce:make-it-easy:4.0.0\n\n## Example ##\n\nConsider the following class hierarchy. This hierarchy illustrates a couple of complicating factors: there is an abstract base class and there is a property (Fruit.ripeness) that is not set via the constructor but by an operation of the Fruit class.\n\n\n```java\npublic abstract class Fruit {\n    private double ripeness = 0.0;\n\n    public void ripen(double amount) {\n        ripeness = Math.min(1.0, ripeness+amount);\n    }\n\n    public boolean isRipe() {\n        return ripeness == 1.0;\n    }\n}\n\npublic class Apple extends Fruit {\n    private int leaves;\n\n    public Apple(int leaves) {\n        this.leaves = leaves;\n    }\n\n    public int numberOfLeaves() {\n        return leaves;\n    }\n}\n\npublic class Banana extends Fruit {\n    public final double curve;\n\n    public Banana(double curve) {\n        this.curve = curve;\n    }\n\n    public double curve() {\n        return curve;\n    }\n}\n```\n\nYou can define Test Data Builders for Apples and Bananas with Make It Easy as follows:\n\n```java\npublic class FruitMakers {\n    public static final Property\u003cFruit,Double\u003e ripeness = newProperty();\n\n    public static final Property\u003cApple, Integer\u003e leaves = newProperty();\n\n    public static final Property\u003cBanana,Double\u003e curve = newProperty();\n\n    public static final Instantiator\u003cApple\u003e Apple = new Instantiator\u003cApple\u003e() {\n        @Override public Apple instantiate(PropertyLookup\u003cApple\u003e lookup) {\n            Apple apple = new Apple(lookup.valueOf(leaves, 2));\n            apple.ripen(lookup.valueOf(ripeness, 0.0));\n            return apple;\n        }\n    };\n\n    public static final Instantiator\u003cBanana\u003e Banana = new Instantiator\u003cBanana\u003e() {\n        @Override public Banana instantiate(PropertyLookup\u003cBanana\u003e lookup) {\n            Banana banana = new Banana(lookup.valueOf(curve, 0.5));\n            banana.ripen(lookup.valueOf(ripeness, 0.0));\n            return banana;\n        }\n    };\n}\n```\n\nAnd use them like this:\n\n```java\nMaker\u003cApple\u003e appleWith2Leaves = an(Apple, with(2, leaves));\nMaker\u003cApple\u003e ripeApple = appleWith2Leaves.but(with(ripeness, 0.9));\nMaker\u003cApple\u003e unripeApple = appleWith2Leaves.but(with(ripeness, 0.125));\n\nApple apple1 = make(ripeApple);\nApple apple2 = make(unripeApple);\n\nBanana defaultBanana = make(a(Banana));\nBanana straightBanana = make(a(Banana, with(curve, 0.0)));\nBanana squishyBanana = make(a(Banana, with(ripeness, 1.0)));\n```\n\nIn contrast, doing so in the style documented in _Growing Object-Oriented Software, Guided by Tests_ would look like this:\n\n```java\npublic interface Builder\u003cT\u003e {\n    T build();\n}\n\npublic class AppleBuilder implements Builder\u003cApple\u003e {\n    private double ripeness = 0.0;\n    private int leaves = 1;\n\n    private AppleBuilder() {}\n\n    public static AppleBuilder anApple() {\n        return new AppleBuilder();\n    }\n\n    public Apple build() {\n        Apple apple = new Apple(leaves);\n        apple.ripen(ripeness);\n        return apple;\n    }\n\n    public AppleBuilder withRipeness(double ripeness){\n        this.ripeness = ripeness;\n        return this;\n    }\n\n    public AppleBuilder withLeaves(int leaves) {\n        this.leaves = leaves;\n        return this;\n    }\n\n    public AppleBuilder but() {\n        return new AppleBuilder()\n                .withRipeness(ripeness)\n                .withLeaves(leaves);\n    }\n}\n\npublic class BananaBuilder implements Builder\u003cBanana\u003e {\n    private double ripeness = 0.0;\n    private double curve = 0.5;\n\n    private BananaBuilder() {}\n\n    public static BananaBuilder aBanana() {\n        return new BananaBuilder();\n    }\n\n    public Banana build() {\n        Banana apple = new Banana(curve);\n        apple.ripen(ripeness);\n        return apple;\n    }\n\n    public BananaBuilder withRipeness(double ripeness){\n        this.ripeness = ripeness;\n        return this;\n    }\n\n    public BananaBuilder withCurve(double curve) {\n        this.curve = curve;\n        return this;\n    }\n\n    public BananaBuilder but() {\n        return new BananaBuilder()\n                .withRipeness(ripeness)\n                .withCurve(curve);\n    }\n}\n```\n\nAnd be used like this:\n\n```java\nAppleBuilder appleWith2Leaves = anApple().withLeaves(2);\nAppleBuilder ripeApple = appleWith2Leaves.but().withRipeness(0.9);\nAppleBuilder unripeApple = appleWith2Leaves.but().withRipeness(0.125);\n\nApple apple1 = ripeApple.build();\nApple apple2 = unripeApple.build();\n\nBanana defaultBanana = aBanana().build();\nBanana straightBanana = aBanana().withCurve(0.0).build();\nBanana squishyBanana = aBanana().withRipeness(1.0).build();\n```\n\nAs you can see, with Make It Easy you have to write a lot less duplicated and boilerplate code.  What duplication there is - in the declaration of anonymous Instantiator classes, for example - can be automatically inserted and refactored by modern IDEs.  (You could also factor out calls to Fruit.ripen to a private helper method, but I left them duplicated for clarity.)\n\nThe full code for this example is [in the Make It Easy repository](src/test/java/example/fruit).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnpryce%2Fmake-it-easy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnpryce%2Fmake-it-easy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnpryce%2Fmake-it-easy/lists"}