Datagen
Java lib that generates random data (numbers, strings, dates) - mostly to facilitate Randomized Testing.
Install / Use
/learn @qala-io/DatagenREADME
Datagen
Java library to generate random data (numbers, strings, dates) - to facilitate Randomized Testing. Randomization may be used to improve coverage, but it can also speed up the process of writing & running tests. Some use cases for randomization:
- Combinatorial Testing - helps reducing the number of test cases you need to write and run
- Fighting with Unique Constraints - do you have a test that registers users with unique username? And the next time you run the test it fails because such user already exists..
- "Wow, I didn't know about that" effect - sometimes randomization may discover tricky cases that you couldn't think of.
- Which one to pick? - often when choosing test data there is no clear winner of what value to pick. Randomization helps with that and ensures we're not prone to Pesticides Effect.
Example
import java.time.OffsetDateTime;
import static io.qala.datagen.RandomDate.beforeNow;
import static io.qala.datagen.RandomShortApi.*;
public class Dog {
private String name;
private OffsetDateTime timeOfBirth;
private double weight;
private double height;
public static Dog random() {
Dog dog = new Dog();
dog.name = alphanumeric(1, 100);
dog.timeOfBirth = nullOr(beforeNow().offsetDateTime());
dog.weight = positiveDouble();
dog.height = positiveInteger();
return dog;
}
}
JUnit5 Integration
@Alphanumeric(min = 2, max = 29, name = "middle value")
@Alphanumeric(length = 30, name = "max boundary")
@English(max=30)
void eachAnnotationInvokesTheTestOnceAndPassesParameters(String value, String name) {
assertTrue(value.length() >= 1 && value.length() <= 31, "Failed case: " + name);
}
@RandomInt(min = 1, name = "greater than zero")
@RandomInt(max = -1, name = "less than zero")
void zeroInt_isNotPassed(int param, String name) {
assertNotEquals(0, param, "Failed case: " + name);
}
Strings
import static io.qala.datagen.RandomValue.*;
import static io.qala.datagen.StringModifier.Impls.*;
import static io.qala.datagen.RandomShortApi.*;
| Flexible API | Short API | Result
|----------------------------------------------------------|----------------------|--------
| length(10).english() |english(10) | "DcRZUNPrED"
| between(1, 10).alphanumeric() |alphanumeric(0, 10) | "zG9G"
| between(1, 10).numeric() |numeric(1, 10) | "7167162"
| length(5).unicode() |unicode(5) | "䂞ꂣ뢧䯺婜"
| length(5).string("A_ B") | | " _B B"
| length(10).with(specialSymbol()).english() | | "hOzKEV#iWv"
| length(10).with(oneOf("_,")).english() | | "dwei,cNTfW"
| length(5).with(spaces()).numeric() | | "874 9 "
| length(3).with(spaceLeft()).english() | | " mT"
| length(4).with(spacesRight(2)).english() | | "hF "
| length(10).with(prefix("BLAH")).numeric() | | "BLAH453677"
| between(1, 10).alphanumerics(4) | | ["cvA", "mTMDj0", "N", ""]
| | mixedCase("blah") | "bLaH"
Nulls & Blanks
| API | Result
|----------------------|------------------------
| nullOrEmpty() | "", null
| nullOrBlank() | "", " ", null
| nullOr(10L) | null, 10L
| nullOr("string") | null, "string"
| blankOr("string") | "", " ", null, "string"
Repeats
import static io.qala.datagen.RandomString.Type.*;
import static io.qala.datagen.RandomValue.*;
import static io.qala.datagen.Repeater.*;
repeat(length(4), NUMERIC).string("-").times(4)`
Result: "9338-8349-6940-7714"
Numbers
import static io.qala.datagen.RandomValue.*;
import static io.qala.datagen.RandomShortApi.*;
|Flexible API | Short API | Result
|---------------------------------------------------------|----------------------|--------
|between(0, 100).integer() | integer(100) | 89
|between(-100, 100).integer() | integer(-100, 100) | -19
| | positiveInteger() | 3432145
| | Long() | 7635811362052252913
| | negativeDouble() | -8.9946257128846746E18
Collections/Arrays
import static io.qala.datagen.RandomElements.*;
import static io.qala.datagen.RandomShortApi.*;
|Flexible API | Short API | Result
|---------------------------------------------------------|----------------------------------------|--------
|from("A", "B", "C", "D").sample() | sample("A", "B", "C") | "C"
|from("A", "B", "C", "D").sample(2) | sampleMultiple(2, "A", "B", "C") | ["B", "A"]
|from("A", "B").sampleWithReplacement(3) | | ["A", "A", "B"]
|from("A", "B", "C").shuffled() | shuffled("A", "B", "C") | ["C", "A", "B"]
Java Date
import static io.qala.datagen.RandomValue.*;
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
between(f.parse("2015-01-01"), f.parse("2016-01-01")).date();
Result: 2015-11-30T08:33:20.349
Java8 DateTime
// Requires Java8 and qala-datagen-java8types dependency
import static io.qala.datagen.RandomDate.*;
API | Result
---------------------------------------------------|--------
plusMinus100Years().zonedDateTime() | 1937-09-27T01:16:15.925440485+01:00[Europe/Belgrade]
since(yearAgo()).instant() | 2015-11-30T08:39:28.397051483Z
before(now()).instant() | -241279778-02-14T16:07:18.061693370Z
between(yearsAgo(2), startOfMonth()).localDate() | 2014-09-30
Booleans
import static io.qala.datagen.RandomShortApi.*;
API | Result
---------------------------------------------------|--------
bool() or weighedTrue(0.5) | false
bools(4) | [false, true, true, false]
nullableBool() | Boolean.TRUE
Functions (for Java8 lambdas)
import static io.qala.datagen.RandomShortApi.*;
Person person = new Person();
callOneOf(() -> person.firstName = english(5),
() -> person.lastName = english(5));
Result: Person[null, "PDGRq"]
callNoneOrMore(() -> person.firstName = english(5),
() -> person.lastName = english(5));
Result: Person[null, null]
callOneOrMore(() -> person.firstName = english(5),
() -> person.lastName = english(5));
Result: Person["LjxYh", "UXoBt"]
Other
- Maven Central coordinates
- Occasional updates are posted in Twitter
- Our blog
Special thanks
To keep the lib tiny and get rid of extra dependencies (there are no transitive dependencies) some of the code was borrowed from these libs: Commons Lang, Commons Math. Hail to open source!
