Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/npryce/make-it-easy
A tiny framework that makes it easy to write Test Data Builders in Java
https://github.com/npryce/make-it-easy
Last synced: 12 days ago
JSON representation
A tiny framework that makes it easy to write Test Data Builders in Java
- Host: GitHub
- URL: https://github.com/npryce/make-it-easy
- Owner: npryce
- Created: 2015-03-14T18:54:40.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2019-09-25T08:56:19.000Z (about 5 years ago)
- Last Synced: 2024-10-15T01:52:06.600Z (29 days ago)
- Language: Java
- Homepage:
- Size: 543 KB
- Stars: 156
- Watchers: 15
- Forks: 7
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
A tiny framework that makes it easy to write Test Data Builders in Java
[![Build Status](https://travis-ci.org/npryce/make-it-easy.svg?branch=master)](https://travis-ci.org/npryce/make-it-easy)
Test 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.
## Download ##
You can download from Maven Central with the artifact coordinates:
com.natpryce:make-it-easy:4.0.0
## Example ##
Consider 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.
```java
public abstract class Fruit {
private double ripeness = 0.0;public void ripen(double amount) {
ripeness = Math.min(1.0, ripeness+amount);
}public boolean isRipe() {
return ripeness == 1.0;
}
}public class Apple extends Fruit {
private int leaves;public Apple(int leaves) {
this.leaves = leaves;
}public int numberOfLeaves() {
return leaves;
}
}public class Banana extends Fruit {
public final double curve;public Banana(double curve) {
this.curve = curve;
}public double curve() {
return curve;
}
}
```You can define Test Data Builders for Apples and Bananas with Make It Easy as follows:
```java
public class FruitMakers {
public static final Property ripeness = newProperty();public static final Property leaves = newProperty();
public static final Property curve = newProperty();
public static final Instantiator Apple = new Instantiator() {
@Override public Apple instantiate(PropertyLookup lookup) {
Apple apple = new Apple(lookup.valueOf(leaves, 2));
apple.ripen(lookup.valueOf(ripeness, 0.0));
return apple;
}
};public static final Instantiator Banana = new Instantiator() {
@Override public Banana instantiate(PropertyLookup lookup) {
Banana banana = new Banana(lookup.valueOf(curve, 0.5));
banana.ripen(lookup.valueOf(ripeness, 0.0));
return banana;
}
};
}
```And use them like this:
```java
Maker appleWith2Leaves = an(Apple, with(2, leaves));
Maker ripeApple = appleWith2Leaves.but(with(ripeness, 0.9));
Maker unripeApple = appleWith2Leaves.but(with(ripeness, 0.125));Apple apple1 = make(ripeApple);
Apple apple2 = make(unripeApple);Banana defaultBanana = make(a(Banana));
Banana straightBanana = make(a(Banana, with(curve, 0.0)));
Banana squishyBanana = make(a(Banana, with(ripeness, 1.0)));
```In contrast, doing so in the style documented in _Growing Object-Oriented Software, Guided by Tests_ would look like this:
```java
public interface Builder {
T build();
}public class AppleBuilder implements Builder {
private double ripeness = 0.0;
private int leaves = 1;private AppleBuilder() {}
public static AppleBuilder anApple() {
return new AppleBuilder();
}public Apple build() {
Apple apple = new Apple(leaves);
apple.ripen(ripeness);
return apple;
}public AppleBuilder withRipeness(double ripeness){
this.ripeness = ripeness;
return this;
}public AppleBuilder withLeaves(int leaves) {
this.leaves = leaves;
return this;
}public AppleBuilder but() {
return new AppleBuilder()
.withRipeness(ripeness)
.withLeaves(leaves);
}
}public class BananaBuilder implements Builder {
private double ripeness = 0.0;
private double curve = 0.5;private BananaBuilder() {}
public static BananaBuilder aBanana() {
return new BananaBuilder();
}public Banana build() {
Banana apple = new Banana(curve);
apple.ripen(ripeness);
return apple;
}public BananaBuilder withRipeness(double ripeness){
this.ripeness = ripeness;
return this;
}public BananaBuilder withCurve(double curve) {
this.curve = curve;
return this;
}public BananaBuilder but() {
return new BananaBuilder()
.withRipeness(ripeness)
.withCurve(curve);
}
}
```And be used like this:
```java
AppleBuilder appleWith2Leaves = anApple().withLeaves(2);
AppleBuilder ripeApple = appleWith2Leaves.but().withRipeness(0.9);
AppleBuilder unripeApple = appleWith2Leaves.but().withRipeness(0.125);Apple apple1 = ripeApple.build();
Apple apple2 = unripeApple.build();Banana defaultBanana = aBanana().build();
Banana straightBanana = aBanana().withCurve(0.0).build();
Banana squishyBanana = aBanana().withRipeness(1.0).build();
```As 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.)
The full code for this example is [in the Make It Easy repository](src/test/java/example/fruit).