Skip to content
This repository was archived by the owner on Aug 13, 2020. It is now read-only.

Commit 014069c

Browse files
authored
Merge pull request #204 from sibyg/master
Add Utility class TypeCheck for type-based testing
2 parents cd24010 + b8cd71d commit 014069c

File tree

6 files changed

+299
-9
lines changed

6 files changed

+299
-9
lines changed

test-utils/test-utils-core/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@
5252
<groupId>org.hamcrest</groupId>
5353
<artifactId>hamcrest-core</artifactId>
5454
</dependency>
55+
<dependency>
56+
<groupId>org.hamcrest</groupId>
57+
<artifactId>hamcrest-library</artifactId>
58+
</dependency>
5559
<dependency>
5660
<groupId>org.mockito</groupId>
5761
<artifactId>mockito-core</artifactId>
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package uk.gov.justice.services.test.utils.core.helper;
2+
3+
import uk.gov.justice.services.test.utils.core.random.Generator;
4+
5+
import java.util.function.Function;
6+
7+
import static java.util.Objects.requireNonNull;
8+
import static org.hamcrest.MatcherAssert.assertThat;
9+
import static org.hamcrest.core.Is.is;
10+
11+
/**
12+
* A Utility class for type-based testing, where a type is a high-level specification of behavior that should hold for a range of data point
13+
*
14+
* @param <T> Type of the Property and must have {@link Generator} implementation for type T
15+
* Usage: typeCheck(RandomGenerator.STRING, s -> s.length() == s.toCharArray().length).withPreCondition(s -> s.length() < 5).verify(times(5));
16+
*/
17+
public class TypeCheck<T> {
18+
19+
private final Generator<T> generator;
20+
private final Function<T, Boolean> condition;
21+
private Function<T, Boolean> preCondition = null;
22+
23+
private TypeCheck(final Generator<T> generator, final Function<T, Boolean> condition) {
24+
requireNonNull(generator, "Generator cannot be null");
25+
requireNonNull(condition, "Condition cannot be null");
26+
this.generator = generator;
27+
this.condition = condition;
28+
}
29+
30+
public static <T> TypeCheck<T> typeCheck(final Generator<T> generator, final Function<T, Boolean> condition) {
31+
return new TypeCheck<T>(generator, condition);
32+
}
33+
34+
public TypeCheck<T> withPreCondition(final Function<T, Boolean> preCondition) {
35+
this.preCondition = preCondition;
36+
return this;
37+
}
38+
39+
public void verify() {
40+
verify(Times.times(1));
41+
}
42+
43+
public void verify(Times times) {
44+
for (int i = 0; i < times.getNum(); i++) {
45+
T next = generator.next();
46+
if (preCondition != null && !preCondition.apply(next)) {
47+
i--;
48+
} else {
49+
assertThat(condition.apply(next), is(true));
50+
}
51+
}
52+
}
53+
54+
public static class Times {
55+
private final int num;
56+
57+
private Times(int num) {
58+
this.num = num;
59+
}
60+
61+
int getNum() {
62+
return num;
63+
}
64+
65+
public static Times times(int times) {
66+
return new Times(times);
67+
}
68+
}
69+
}
70+

test-utils/test-utils-core/src/main/java/uk/gov/justice/services/test/utils/core/random/Generator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@
99
*/
1010
public abstract class Generator<T> {
1111
final Random RANDOM = new java.util.Random();
12-
abstract T next();
12+
public abstract T next();
1313
}

test-utils/test-utils-core/src/main/java/uk/gov/justice/services/test/utils/core/random/RandomGenerator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public class RandomGenerator {
1818
public static final Generator<Double> DOUBLE = new DoubleGenerator(Integer.MAX_VALUE, 2);
1919
public static final Generator<String> EMAIL_ADDRESS = new EmailAddressGenerator();
2020
public static final Generator<Integer> INTEGER = new IntegerGenerator(Integer.MAX_VALUE);
21-
public static final Generator<String> STRING = new StringGenerator(10);
21+
public static final Generator<String> STRING = new StringGenerator();
2222
public static final Generator<Long> LONG = new LongGenerator();
2323
public static final Generator<BigDecimal> PERCENTAGE = new BigDecimalGenerator(100, 2);
2424
public static final Generator<String> NI_NUMBER = new NiNumberGenerator();
@@ -28,7 +28,7 @@ public class RandomGenerator {
2828
public static final Generator<LocalDate> FUTURE_LOCAL_DATE = new LocalDateGenerator(Period.ofYears(5), LocalDate.now(), LocalDateGenerator.Direction.FORWARD);
2929
public static final Generator<LocalDate> PAST_LOCAL_DATE = new LocalDateGenerator(Period.ofYears(5), LocalDate.now(), LocalDateGenerator.Direction.BACKWARD);
3030

31-
public static Generator<String> string(Integer length) {
31+
public static Generator<String> string(int length) {
3232
return new StringGenerator(length);
3333
}
3434

test-utils/test-utils-core/src/main/java/uk/gov/justice/services/test/utils/core/random/StringGenerator.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,22 @@
22

33
import static org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric;
44

5+
/**
6+
* Maximum length supported is 10
7+
*/
58
public class StringGenerator extends Generator<String> {
6-
private final Integer length;
79

8-
public StringGenerator(final Integer length) {
9-
if (length != null) {
10-
this.length = length;
11-
} else {
12-
this.length = 3;
10+
private static final int MAX_LENGTH = 10;
11+
private int length = MAX_LENGTH;
12+
13+
public StringGenerator() {
14+
}
15+
16+
public StringGenerator(final int length) {
17+
if (length > MAX_LENGTH) {
18+
throw new IllegalArgumentException("Max supported length is " + MAX_LENGTH);
1319
}
20+
this.length = length;
1421
}
1522

1623
@Override
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
package uk.gov.justice.services.test.utils.core.random;
2+
3+
import com.google.common.collect.Lists;
4+
import org.junit.Test;
5+
6+
import java.math.BigDecimal;
7+
import java.net.URI;
8+
import java.time.LocalDate;
9+
import java.util.List;
10+
import java.util.Objects;
11+
import java.util.UUID;
12+
13+
import static uk.gov.justice.services.test.utils.core.helper.TypeCheck.Times.times;
14+
import static uk.gov.justice.services.test.utils.core.helper.TypeCheck.typeCheck;
15+
16+
public class RandomGeneratorTest {
17+
18+
private static final int NUMBER_OF_TIMES = 10;
19+
20+
@Test
21+
public void shouldGenerateRandomBigDecimal() {
22+
// given
23+
final Generator<BigDecimal> bigDecimalGenerator = RandomGenerator.BIG_DECIMAL;
24+
25+
// when
26+
typeCheck(bigDecimalGenerator, s -> bigDecimalGenerator.next().compareTo(bigDecimalGenerator.next()) != 0).verify(times(NUMBER_OF_TIMES));
27+
}
28+
29+
@Test
30+
public void shouldGenerateRandomDouble() {
31+
// given
32+
final Generator<Double> doubleGenerator = RandomGenerator.DOUBLE;
33+
34+
// when
35+
typeCheck(doubleGenerator, s -> !Objects.equals(doubleGenerator.next(), doubleGenerator.next())).verify(times(NUMBER_OF_TIMES));
36+
}
37+
38+
@Test
39+
public void shouldGenerateRandomEmailAddress() {
40+
// given
41+
final Generator<String> emailAddressGenerator = RandomGenerator.EMAIL_ADDRESS;
42+
43+
// when
44+
typeCheck(emailAddressGenerator, s -> !emailAddressGenerator.next().equals(emailAddressGenerator.next())).verify(times(NUMBER_OF_TIMES));
45+
}
46+
47+
@Test
48+
public void shouldGenerateRandomInteger() {
49+
// given
50+
final Generator<Integer> integerGenerator = RandomGenerator.INTEGER;
51+
52+
// when
53+
typeCheck(integerGenerator, s -> !Objects.equals(integerGenerator.next(), integerGenerator.next())).verify(times(NUMBER_OF_TIMES));
54+
}
55+
56+
@Test
57+
public void shouldGenerateRandomString() {
58+
// given
59+
final Generator<String> stringGenerator = RandomGenerator.STRING;
60+
61+
// when
62+
typeCheck(stringGenerator,
63+
s -> !stringGenerator.next().equals(stringGenerator.next()))
64+
.verify(times(NUMBER_OF_TIMES));
65+
}
66+
67+
@Test
68+
public void shouldGenerateRandomLong() {
69+
// given
70+
final Generator<Long> longGenerator = RandomGenerator.LONG;
71+
72+
// when
73+
typeCheck(longGenerator, s -> !Objects.equals(longGenerator.next(), longGenerator.next())).verify(times(NUMBER_OF_TIMES));
74+
}
75+
76+
@Test
77+
public void shouldGenerateRandomPercentage() {
78+
// given
79+
final Generator<BigDecimal> percentageGenerator = RandomGenerator.PERCENTAGE;
80+
81+
// when
82+
typeCheck(percentageGenerator, s -> percentageGenerator.next().compareTo(percentageGenerator.next()) != 0).verify(times(NUMBER_OF_TIMES));
83+
}
84+
85+
@Test
86+
public void shouldGenerateRandomNiNumber() {
87+
// given
88+
final Generator<String> niNumberGenerator = RandomGenerator.NI_NUMBER;
89+
90+
// when
91+
typeCheck(niNumberGenerator, s -> !niNumberGenerator.next().equals(niNumberGenerator.next())).verify(times(NUMBER_OF_TIMES));
92+
}
93+
94+
@Test
95+
public void shouldGenerateRandomPostCode() {
96+
// given
97+
final Generator<String> postCodeGenerator = RandomGenerator.POST_CODE;
98+
99+
// when
100+
typeCheck(postCodeGenerator, s -> !postCodeGenerator.next().equals(postCodeGenerator.next())).verify(times(NUMBER_OF_TIMES));
101+
}
102+
103+
@Test
104+
public void shouldGenerateRandomUri() {
105+
// given
106+
final Generator<URI> uriGenerator = RandomGenerator.URI;
107+
108+
// when
109+
typeCheck(uriGenerator, s -> !uriGenerator.next().equals(uriGenerator.next())).verify(times(NUMBER_OF_TIMES));
110+
}
111+
112+
@Test
113+
public void shouldGenerateRandomUuid() {
114+
// given
115+
final Generator<UUID> uuidGenerator = RandomGenerator.UUID;
116+
117+
// when
118+
typeCheck(uuidGenerator, s -> !uuidGenerator.next().equals(uuidGenerator.next())).verify(times(NUMBER_OF_TIMES));
119+
}
120+
121+
@Test
122+
public void shouldGenerateRandomForwardDate() {
123+
// given
124+
final Generator<LocalDate> futureLocalDateGenerator = RandomGenerator.FUTURE_LOCAL_DATE;
125+
126+
// when
127+
typeCheck(futureLocalDateGenerator, s -> !futureLocalDateGenerator.next().isEqual(futureLocalDateGenerator.next())).verify(times(NUMBER_OF_TIMES));
128+
}
129+
130+
@Test
131+
public void shouldGenerateRandomBackwardDate() {
132+
// given
133+
final Generator<LocalDate> pastLocalDateGenerator = RandomGenerator.PAST_LOCAL_DATE;
134+
135+
// when
136+
typeCheck(pastLocalDateGenerator, s -> !pastLocalDateGenerator.next().isEqual(pastLocalDateGenerator.next())).verify(times(NUMBER_OF_TIMES));
137+
}
138+
139+
@Test
140+
public void shouldGenerateStringOfLength() {
141+
final Generator<String> stringOfLength5Generator = RandomGenerator.string(5);
142+
typeCheck(stringOfLength5Generator, s -> (!(stringOfLength5Generator.next().length() < 5))).verify(times(NUMBER_OF_TIMES));
143+
}
144+
145+
@Test
146+
public void shouldGenerateValuesFromIterable() {
147+
// given
148+
final List<Integer> integers = Lists.newArrayList(1, 2, 3, 4, 5);
149+
// and
150+
final Generator<Integer> valuesGenerator = RandomGenerator.values(integers);
151+
152+
// when
153+
typeCheck(valuesGenerator, s -> ((integers.contains(valuesGenerator.next())))).verify(times(NUMBER_OF_TIMES));
154+
}
155+
156+
@Test
157+
public void shouldGenerateIntegerEqualToOrLessThanMax() {
158+
// given
159+
final Integer max = 100;
160+
// and
161+
final Generator<Integer> integerWithMaxGenerator = RandomGenerator.integer(max);
162+
163+
// when
164+
typeCheck(integerWithMaxGenerator, s -> ((integerWithMaxGenerator.next() <= max))).verify(times(NUMBER_OF_TIMES));
165+
}
166+
167+
@Test
168+
public void shouldGenerateBigDecimalEqualToOrLessThanMax() {
169+
// given
170+
final Integer max = 100;
171+
// and
172+
final Generator<BigDecimal> bigDecimalWithMaxGenerator = RandomGenerator.bigDecimal(max);
173+
174+
// when
175+
typeCheck(bigDecimalWithMaxGenerator,
176+
s -> ((bigDecimalWithMaxGenerator.next().compareTo(new BigDecimal(max)) != 1))).verify(times(NUMBER_OF_TIMES));
177+
}
178+
179+
@Test
180+
public void shouldGenerateBigDecimalBelowMaxAndDecimalPlaces() {
181+
// given
182+
final Integer max = 100;
183+
// and
184+
final Integer decimalPlaces = 2;
185+
// and
186+
final Generator<BigDecimal> bigDecimalWithMaxAndDecimalGenerator = RandomGenerator.bigDecimal(max, decimalPlaces);
187+
188+
189+
// when
190+
typeCheck(bigDecimalWithMaxAndDecimalGenerator,
191+
s -> ((bigDecimalWithMaxAndDecimalGenerator.next().compareTo(new BigDecimal(max + "." + decimalPlaces)) != 1)))
192+
.verify(times(NUMBER_OF_TIMES));
193+
}
194+
195+
@Test
196+
public void shouldGenerateDoubleBelowMaxAndDecimalPlaces() {
197+
// given
198+
final Integer max = 100;
199+
// and
200+
final Integer decimalPlaces = 2;
201+
// and
202+
final Generator<Double> doubleWithMaxAndDecimalGenerator = RandomGenerator.doubleval(max, decimalPlaces);
203+
204+
// when
205+
typeCheck(doubleWithMaxAndDecimalGenerator,
206+
s -> ((doubleWithMaxAndDecimalGenerator.next().compareTo(Double.parseDouble(max + "." + decimalPlaces)) != 1)))
207+
.verify(times(NUMBER_OF_TIMES));
208+
}
209+
}

0 commit comments

Comments
 (0)