How to create Test Data in Jakarta EE applications

This article covers how to create sample random Data for your REST Services using a well-known library Data Faker. We will show how to bind a Fake Model to our Entity so that you can create sample Test Data in a snap!

In the first article of this series ( Generating Random data for REST Services: Part one ) we have learned how to use some linux command line tools to test our REST Services using curl. This approach is plain and simple however it does not provide realistic data for our Services.

Introducing DataFaker Java Testing Library

DataFaker goes beyond the conventional approach of using static or manually crafted data for testing. It enables developers and QA engineers to create dynamic and lifelike datasets on-the-fly, ensuring a more accurate representation of real-world scenarios.

Firstly, to get started with DataFaker you need to provide a single Library to your application:

<dependency>
    <groupId>net.datafaker</groupId>
    <artifactId>datafaker</artifactId>
    <version>1.9.0</version>
</dependency>

Once that you have the library in your Classpath then you can create an instance of Faker and use it to produce random data for any of the available Providers. For example, to use the Name provider which belongs to the Base Provider Group you can just do the following:

import net.datafaker.Faker;

Faker faker = new Faker();

String name = faker.name().fullName();
String firstName = faker.name().firstName(); 
String lastName = faker.name().lastName(); 

This example, however, is just scratching the surface. You can do much more. For example, you can bind one of your Beans with a Schema from Data Faker. In the next section we will learn how to do it.

Faking Entity Bean Data

In this example, we will use DataFaker in the context of a Jakarta EE application to demonstrate how useful it can be in the testing phase. Let’s begin by adding the @FakeForSchema in our Entity Class:

@Entity
@FakeForSchema("com.mastertheboss.model.CustomerSchema#defaultSchema") 
public class Customer {
    @Id
    @SequenceGenerator(
            name = "customerSequence",
            sequenceName = "customerId_seq",
            allocationSize = 1,
            initialValue = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "customerSequence")
    private Long id;
    @Column(length = 40)
    private String name;
    @Column(length = 40)
    private String surname;
    
    // Getters/Setters omitted for brevity

}

The @FakeForSchema annotation specifies a schema for generating fake data using the Java Faker library. The schema defines the structure and constraints of the desired data, ensuring that it adheres to specific rules and patterns.

Then, let’s create the schema by adding the com.mastertheboss.model.CustomerSchema Class:

public class CustomerSchema {
      public static Schema<Object, ?> defaultSchema() {
         var faker = new Faker(Locale.getDefault(), ThreadLocalRandom.current());
            return Schema.of(
            field("name", () -> faker.name().firstName()),
            field("surname", () -> faker.name().lastName())
            );
      }
    
}

The CustomerSchema Class contains the mapping between the Customer Entity and the Faker Providers. As you can see, we are mapping name with the firstName() function and surname with lastName().

Our application also includes a Repository Class to perform operations against the Database and a Controller which maps each of these operations. This application part does not however contain any change so you can just grab it from the source download link.

Coding the Test Client

Then, after deploying the server application we will code a client to Test it. For this purpose, we will be using RESTAssured which is a great fit for testing REST Content.

If you are new to RESTAssured we recommend checking this article: How to test REST Services with RestAssured

@BeforeAll
public static void start() throws Exception {

	RestAssured.baseURI = "http://localhost:8080/datafaker/rest";
}

@Test
public void testRandomData() throws Exception {
	Customer client = BaseFaker.populate(Customer.class);

	// Convert the Java object to JSON
	ObjectMapper mapper = new ObjectMapper();
	String json = mapper.writeValueAsString(client);

	// Create and execute the POST request
	Response response = RestAssured
			.given()
			.contentType("application/json")
			.body(json)
			.post("/customers");

	// Verify the response status code
	response.then().statusCode(201);

	Response response2 = RestAssured.given()
			.contentType(ContentType.JSON)
			.when()
			.get("/customers")
			.then()
			.extract().response();

	Assertions.assertEquals(200, response2.statusCode());
	System.out.println(response2.jsonPath().prettify());

	RestAssured.given()

			.when().get("/customers")
			.then()
			.statusCode(200);

}

The most interesting part is the following line of code:

Customer client = BaseFaker.populate(Customer.class);

In practice, we are creating a new Customer object using the CustomerSchema structure that our Entity knows about. This way, our Customer object already contains all the properties we need for testing! By adding one GET subsequent Request we can verify that Customer list:

fake data java test

Moving the Fake Logic on the Client side

In this example, our Schema sits on the server side and matches with the Entity Bean. That’s great if your server side structure seldom changes. If you prefer, you can define the Schema on the Client side as well. For example, you can define your Schema in the Test Class much the same way:

BaseFaker faker = new BaseFaker(new ThreadLocalRandom.current());
	  
Schema<Object, ?> schema = Schema.of(
field("name", () -> faker.name().firstName()),
field("surname", () -> faker.name().lastName())
);
	  
JsonTransformer<Object> transformer = JsonTransformer.builder().build();
String json = transformer.generate(schema, 1);

Response response = RestAssured
 .given()
 .contentType("application/json")
 .body(json)
 .post("/customers");

Also notice here we are using a Transformer Class to create JSON Content from the Schema. There are several built-in Transformers ( CSV,JSON, SQL, YAML, XML, Java Object) which you can use to produce directly the content in a particular format.

Using Sequences

Finally, it is worth mentioning that you can also build Collection of your data using the collection static method:

 List<String> names = 
    faker.collection(
            () -> faker.name().firstName(), 
            () -> faker.address().streetAddress())
        .len(2, 5)
        .generate();
        System.out.println(names);

The above example will generate from 2 to 5 random attributes from the one mentioned. For example, in our case:

[Darron, Monty, 014 Abbott Crossroad, 6683 Keena Junctions]

Conclusion

DataFaker seamlessly integrates with popular testing frameworks, making it easy to incorporate dynamic data generation into your existing test suites. Whether you are using JUnit, TestNG, or another framework, DataFaker plays well with others, enhancing the versatility of your testing ecosystem.

Many thanks to Sergey Nuyanzin for providing tips on how to use Random Data Generation in my example!

Source code: https://github.com/fmarchioni/mastertheboss/tree/master/test/datafaker