DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Building a Real-Time Change Data Capture Pipeline With Debezium, Kafka, and PostgreSQL
  • Supervised Fine-Tuning (SFT) on VLMs: From Pre-trained Checkpoints To Tuned Models
  • Enhancing Business Decision-Making Through Advanced Data Visualization Techniques
  • Exploring Intercooler.js: Simplify AJAX With HTML Attributes

Trending

  • Scaling Microservices With Docker and Kubernetes on Production
  • Rust, WASM, and Edge: Next-Level Performance
  • Chat With Your Knowledge Base: A Hands-On Java and LangChain4j Guide
  • Monolith: The Good, The Bad and The Ugly
  1. DZone
  2. Data Engineering
  3. Data
  4. Generating and Mocking Data With MockNeat

Generating and Mocking Data With MockNeat

Let's take a look at MockNeat — a new library designed to help you generate and mock app data tailored to fit your business requirements.

By 
Andrei Ciobanu user avatar
Andrei Ciobanu
·
Jan. 01, 18 · Tutorial
Likes (10)
Comment
Save
Tweet
Share
25.6K Views

Join the DZone community and get the full member experience.

Join For Free

MockNeat is a new Java 8+ library that can be used to provision apps with initial sets of data that are valid from a business standpoint.

Data is arbitrarily generated by matching a set of criteria that can be programmatically defined, allowing developers enough flexibility to obtain specific arbitrary results matching their business needs.

Let's start with a simple example where we generate a List<String>, where each String contains a first and last name concatenated with a random number. Additional constraints:

  • The first name is in lower case letters;
  • The last name is in upper case letters;
  • The random number has a:
    • 30% chance of being in the [0, 10) range;
    • 70% chance of being in the [10, 20) range;
  • The list contains exactly 1000 strings.

With MockNeat, all we need to do is:

MockNeat m = MockNeat.threadLocal();

// Create the random number generator
MockUnitInt num = m.probabilites(Integer.class)
                           .add(0.3, m.ints().range(0, 10))
                           .add(0.7, m.ints().range(10, 20))
                           .mapToInt(Integer::intValue);

// Creates the arbitrary strings and keep them in a List
List<String> strings = m.fmt("#{first} #{last} #{num}")
                                .param("first", m.names().first().format(LOWER_CASE))
                                .param("last", m.names().last().format(UPPER_CASE))
                                .param("num", num)
                                .list(1000)
                                .val();


Possible output:

karol KUMFER 15
rosita SCHNITTKER 15
cori RULON 12 
ilda HERMEZ 11
jon ZECCHINI 19
...


Installation

If you use Gradle in your projects, add the following dependency to the Gradle build file:

repositories { jcenter() }
dependencies { compile 'net.andreinc.mockneat:mockneat:0.1.3' }


And here is the equivalent Maven pom.xml dependency:

<repositories>
    <repository>
        <id>jcenter</id>
        <url>https://jcenter.bintray.com/</url>
    </repository>
</repositories>

<dependencies>
    <dependency>
        <groupId>net.andreinc.mockneat</groupId>
        <artifactId>mockneat</artifactId>
        <version>0.1.3</version>
    </dependency>
</dependencies>


For the latest version, always check the existing jcenter() repository. The current version (0.1.3 at time of writing) should be stable enough, but the library is being actively developed, so it's best to keep an eye on new releases.

Getting Started

The starting point of the library is the MockNeat.java class.

The simplest way to obtain a MockNeat instance is to re-use one of the "pre-defined" ones:

/** Internally uses the ThreadLocalRandom implementation */
MockNeat mock = MockNeat.threadLocal();

/** Internally uses the SecureRandom implementation */
MockNeat mock = MockNeat.secure();

/** Internally uses the classical Random implementation */
MockNeat mock = MockNeat.old();


Once we have the instance, we can start generating our first types of data:

// Generating an arbitrary integer in the range [200, 100) and then divide it by 5
Integer int1 = mock.ints()
                   .range(100, 200)
                   .map(i -> i / 5)
                   .val();

// Possible Output: 35
// Generate an IPV4 address of Class A or CLASS C
String ipv4ClassA = mock.ipv4s()
                        .types(CLASS_A, CLASS_C)
                        .val();

// Possible Output: 213.25.234.95


To see a complete list of all the types of data that can be generated, please check the official documentation. The library covers, by default, a comprehensive list for generating primitives values, financial data, networking data, user-related data, geographical data, etc.

Everything Is a MockUnit<T>

The way the data is obtained is by chaining a set of constraints (like we did with the range(), type(), etc. in the previous examples). Each method in the chain passes the behavior to the next one while re-using the behavior of the previous one.

In all examples, you will see the val() method called last. This is the closing method of the chain, the one that generates the actual value.

All generators implement the functional interface MockUnit<T>. The full documentation on this interface can be found here.

Once we've configured a generator, we can keep referencing it and re-use it to obtain multiple values:

// Creates a MockUnitInt that generates
// integers in the interval [0, 10)
MockUnitInt integers = mock.ints().bound(10);

// Each subsequent call to val() returns a different value
int x1 = integers.val(),    
    x2 = integers.val(),    
    x3 = integers.val();

System.out.printf("%d %d %d\n", x1, x2, x3);

// Possible Output:
// 7 3 4


We can re-use the generators further. Collections and arrays can also be created by translating the previous behavior of a MockUnit<T> into a new MockUnit<List<T>> and so on:

// Generator of integer values
MockUnitInt integers = mock.ints().bound(10);

// Generates a primitive int array of length 10 
// where all the integers are between [0, 10)
int[] arr1 = integers.arrayPrimitive(10).val();

// Generates an Integer[] array of length 10
// where all the integers are between [0, 10)
Integer[] arr2 = integers.array(10).val();

// Generates a LinkedList of size 10
// where all the integers are between [0, 10)
List<Integer> list1 = integers.list(LinkedList.class, 10).val();

// Generate a List<List<Integer>>
// where all the integers from the enclosed lists
// are between [0, 10)
List<List<Integer>> list2 = integers.list(10).list(10).val();


As you can see in the last example, complex data structures can be instantly created.

Let's assume we want to mock a shocking structure like a Map<String, List<Map<Set<Integer>, List<Integer>>>>. Normally you shouldn't have something like that in a real-world application, so this is for demonstration purposes only:

Map<String, List<Map<Set<Integer>, List<Integer>>>> result = 
                mock.ints() // A MockUnitInt that randomly generates Integers
                    .list(2) // Translates to MockUnit<List<Int>>
                    .mapKeys(2, mock.ints().set(3)::val) // Translates to MockUnit<Map<Set<Integer>, List<Integer>>>
                    .list(LinkedList.class, 2) // Translates to MockUnit<List<Map<Set<Integer>, List<Integer>>>>
                    .mapKeys(4, mock.strings()::val) // Translates to MockUnit<Map<String, List<Map<Set<Integer>, List<Integer>>>>>
                    .val(); // Gets a single value from the generator (MockUnit<..>)


By morphing into a different MockUnit<T1 - T2 -...-Tn> each time we, can build crazy structures filled with arbitrary data defined by our initial sets of constraints.

Normally, this should cover the basic needs for mocking complex objects from your model layers.

Mocking Real-Life Objects

Let's assume we have two classes — User and Group — that are associated through the groupId field (each user belongs to a group, and the groupId on the User class acts like a foreign key).

// No Arg Constructor
// Getters and Setters
public class User {    
  private Long id;    
  private Long groupId;    
  private String email;
}

// No Arg Constructor
// Getters and Setters
public class Group {
    private Long id;
    private String name;
}


We can use the reflect() method to mock the objects. This method internally uses the Reflection API.

First, we create a list of groups with random names in the following format: "Group [A-Z]{3}[0-0]{2}" (using the regex() method, we can generate arbitrary something that matches a given regular expression).

The groupId values will be a sequence of numbers [100, 200, 300, 400, ...].

// Create a list of 5 groups 
List<Group> groups = mock.reflect(Group.class)
                         .field("id", mock.longSeq().start(100).increment(100))
                         .field("name", mock.regex("Group [A-Z]{3}[0-9]{2}"))
                         .list(5)
                         .val();

// Output
// [Group{id=100, name='Group VTD01'}, Group{id=200, name='Group OOK98'}, Group{id=300, name='Group LKE18'}, Group{id=400, name='Group KMU53'}, Group{id=500, name='Group HCE89'}]


The second step is to create the list of 100 Users referencing the groupId from the previous example:

// Generating 100 users
List<User> users = mock.reflect(User.class)
                       .field("id", mock.longSeq())
                       .field("groupId", mock.from(groups).map(Group::getId))
                       .field("email", mock.emails())
                       .list(100)
                       .val();

// Possible Output:
// [User{id=0, groupId=500, email='darnedjeffery@hotmail.co.uk'}, User{id=1, groupId=300, email='bluntisabell@mail.com'}, User{id=2, groupId=300, email='beigeerin@hotmail.co.uk'}, ... ]


Going Further: Generating CSV Files With Arbitrary Data

In the following example, we are going to generate a .csv file contain "financial information" for a set of random individuals.

The format of the CSV file is as follows:

id, firstName, lastName, email, salary, creditCardNum


We will use the following methods:

  • longSeq() to generate the id;
  • names().first() to generate the firstName;
  • names().last() to generate the lastName;
  • emails() to generate the email;
  • ints().range() to generate the salary;
  • creditCards() to generate the creditCardNum;

The solution:

MockNeat m = MockNeat.threadLocal();

final Path path = Paths.get("./test.csv");

m.fmt("#{id},#{first},#{last},#{email},#{salary},#{creditCardNum}")
                .param("id", m.longSeq().start(10).increment(10))
                .param("first", m.names().first())
                .param("last", m.names().last())
                .param("email", m.emails().domain("company.com"))
                .param("salary", m.ints().range(1000, 5000))
                .param("creditCardNum", m.creditCards().type(AMERICAN_EXPRESS))
                .list(1000)
                .consume(list -> {
                    try { Files.write(path, list, CREATE, WRITE); }
                    catch (IOException e) { e.printStackTrace(); }
                });


And the results are as follows:

10,Zandra,Sprenger,triedshakira@company.com,2578,371618033623968
20,Davina,Shamapande,lothadelia@company.com,4953,373956318938315
30,Cinthia,Brotherton,hetnicklaw@company.com,1921,377270429060092
40,Ashton,Rochkes,skintbirches@company.com,3318,373400437933865
50,Mammie,Scagliotti,chargedsigrid@company.com,4719,375698819073725
60,Leone,Rings,deafclifford@company.com,4311,344775717545851
70,Mika,Tengan,limbedtimmy@company.com,3993,378324590541684
80,Shaun,Starns,featdart@company.com,4750,375645508553061
90,Ninfa,Dompe,markedpozzies@company.com,3630,346404509489586
100,Lea,Genzone,softlyprigs@company.com,4667,372555622778341
110,Michal,Boesen,fierceeileen@company.com,3692,343596540625129
120,Prudence,Perro,wholesaleflues@company.com,2761,374100480248117
130,Tena,Carl,wingedsuzann@company.com,4437,374096736417177
140,Temeka,Wools,ainkim@company.com,2087,372318008657138
150,Marybeth,Piepenbrink,frorelenard@company.com,3623,348735745292633
160,Dorie,Lippard,cheerlessolivares@company.com,1786,378499736153337
170,Joann,Boardman,plunktransects@company.com,1432,347952346559697
...


Going Further: Generating JSON Strings

By default, MockNeat doesn't support JSON transformations at the MockUnit interface level. The solution is to work with one of the existing libraries. For simplicity, in the following example, we are going to use gson.

The model classes are as follows:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Profile {
    Integer profileId;
    Date profileAdded;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserProfile {
    String name;
    String userName;
    String email;
    List<Profile> profiles;
}


The easiest way to generate a JSON String from the UserProfile class:

MockNeat mockNeat = MockNeat.threadLocal();
Gson gson = new GsonBuilder()
                        .setPrettyPrinting()
                        .create();

String json = mockNeat
                     .reflect(UserProfile.class)
                     .field("name", mockNeat.names().full())
                     .field("userName", mockNeat.users())
                     .field("email", mockNeat.emails())
                     .field("profiles",
                                mockNeat.reflect(Profile.class)
                                        .field("profileId", mockNeat.ints().range(100, 1000))
                                        .field("profileAdded", mockNeat.localDates().toUtilDate())
                                        .list(2))
                     .map(gson::toJson) /* Transforms the UserProfile class into a 'pretty' json. */
                     .val();

System.out.println(json);


And the possible output:

{
  "name": "Cecila Starbird",
  "userName": "moistben",
  "email": "randiexyst@hotmail.co.uk",
  "profiles": [
    {
      "profileId": 964,
      "profileAdded": "Mar 19, 1973 12:00:00 AM"
    },
    {
      "profileId": 854,
      "profileAdded": "Jun 3, 1978 12:00:00 AM"
    }
  ]
}


Data (computing)

Opinions expressed by DZone contributors are their own.

Related

  • Building a Real-Time Change Data Capture Pipeline With Debezium, Kafka, and PostgreSQL
  • Supervised Fine-Tuning (SFT) on VLMs: From Pre-trained Checkpoints To Tuned Models
  • Enhancing Business Decision-Making Through Advanced Data Visualization Techniques
  • Exploring Intercooler.js: Simplify AJAX With HTML Attributes

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!