In this article Java Unit Tests make easy – Random Values with PODAM, we discuss how to generate random values to object, collections we use on Junit test using PODAM library.

When we write unit test cases for functions, a big headache for developers is filling mock data to our objects, collections etc.

For example, let see what would be the test case to fetch an object from a function. 

Please look below code snippet. In this object contains the list of child objects too.

@Test
  void testFindAuthorByUserId() {
    when(authorRepository.findById(anyLong()))
        .thenReturn(
            new AuthorDoc(
                Long.valueOf(1),
                "orgCode",
                "firstName",
                "lastName",
                new GregorianCalendar(2020, Calendar.DECEMBER, 14, 10, 50).getTime(),
                "email",
                Arrays.asList(
                    new BookDoc(
                        Long.valueOf(1),
                        "book Name 1",
                        "isbn1",
                        LocalDateTime.of(2020, Month.DECEMBER, 14, 10, 50, 28),
                        LocalDateTime.of(2020, Month.DECEMBER, 14, 10, 50, 28),
                        "createdBy",
                        "modifiedBy"),
                    new BookDoc(
                        Long.valueOf(2),
                        "book Name 2",
                        "isbn2",
                        LocalDateTime.of(2020, Month.DECEMBER, 14, 10, 50, 28),
                        LocalDateTime.of(2020, Month.DECEMBER, 14, 10, 50, 28),
                        "createdBy",
                        "modifiedBy")),
                LocalDateTime.of(2020, Month.DECEMBER, 14, 10, 50, 28),
                LocalDateTime.of(2020, Month.DECEMBER, 14, 10, 50, 28),
                "createdBy",
                "modifiedBy"));

    AuthorDto result = authorService.findAuthorByUserId(Long.valueOf(1));
    Assertions.assertEquals(
        new AuthorDto(
            Long.valueOf(1),
            "orgCode",
            "firstName",
            "lastName",
            new GregorianCalendar(2020, Calendar.DECEMBER, 14, 10, 50).getTime(),
            "email",
            Arrays.asList(
                new BookDto(Long.valueOf(1), "book Name 1", "isbn1"),
                new BookDto(Long.valueOf(2), "book Name 2", "isbn2"))),
        result);
  }

In this code snippet, we can see a lot of hardcode data we have to use to fill the object with values.

Now let see what we can do for this matter… 

 Any good solution??

Yes, we have PODAM.

What is PODAM?

PODAM is a lightweight tool to auto-fill Java POJOs with data. This comes handy when developing unit tests. Thanks to PODAM users now have a one-liner that does all the work them.

What are the features of PODAM:

  • Automatic introspection of your POJOs to fill all possible attributes with random data. You can customise this behaviour.
  • Extension points to customise the data strategy, fields exclusions based on names or annotations
  • Support for your custom annotations to either provide data or exclude fields
  • The option to select minimal constructors (for lightweight POJOs) or full constructors
  • And Support for Java types, enumerations, arrays, collections (lists, sets, maps)
  • Also Support for generics
  • Support for your factories when PODAM cannot introspect enough information to generate a type (e.g. XMLGregorianCalendar)
  • Support for arbitrary method executions when the typical lifecycle has ended

Using PODAM in Spring boot application

We have to add podam dependencies to the spring boot project.

Please use the latest version. When I’m writing this article, the latest version is 7.2.5.RELEASE

For Maven

<dependency>
    <groupId>uk.co.jemos.podam</groupId>
    <artifactId>podam</artifactId>
    <version>7.2.5.RELEASE</version>
    <scope>test</scope>
</dependency>

For Gradle

testCompile group: 'uk.co.jemos.podam', name: 'podam', version: '7.2.5.RELEASE'

Now we are going to refactor the above mentions code using Podam.

Pojo using podom

  @Test
  void testFindAuthorByUserId() {
    PodamFactory factory = new PodamFactoryImpl();
    AuthorDoc authorDoc = factory.manufacturePojo(AuthorDoc.class);

    when(authorRepository.findById(anyLong())).thenReturn(authorDoc);

    AuthorDto result = authorService.findAuthorByUserId(Long.valueOf(1));
    Assertions.assertEquals(authorDoc.getUserId(), result.getUserId());
    Assertions.assertEquals(authorDoc.getFirstName(), result.getFirstName());
    Assertions.assertEquals(authorDoc.getBooks().size(), result.getBooks().size());
  }

Can you believe this?
46 line of code we reduce to less than ten lines.
Let’s see what happen there. Let’s break down.

First, we implement PodamFactory instance.

PodamFactory factory = new PodamFactoryImpl();

Then using the above PodamFactory, we can create an object with values.

AuthorDoc authorDoc = factory.manufacturePojo(AuthorDoc.class);

if we debug this, we can see the assigned values to the object like below

Values inside object assign from Podam

Let see more examples

List (String) using podom

Let’s see how we can build a List of String using Podam.

PodamFactory factory = new PodamFactoryImpl();
List<String> authorNames = factory.manufacturePojo(ArrayList.class, String.class);

List (Pojo) using podom

If we need to test some function with the list object, it is an immense pain.

@Test
  void testFindByOrgCode() {
    when(authorRepository.findByOrgCode(anyString()))
        .thenReturn(
            Arrays.asList(
                new AuthorDoc(
                    Long.valueOf(1),
                    "orgCode",
                    "firstName",
                    "lastName",
                    new GregorianCalendar(2020, Calendar.DECEMBER, 14, 10, 50).getTime(),
                    "email",
                    Arrays.asList(
                        new BookDoc(
                            Long.valueOf(1),
                            "book Name 1",
                            "isbn1",
                            LocalDateTime.of(2020, Month.DECEMBER, 14, 10, 50, 28),
                            LocalDateTime.of(2020, Month.DECEMBER, 14, 10, 50, 28),
                            "createdBy",
                            "modifiedBy"),
                        new BookDoc(
                            Long.valueOf(2),
                            "book Name 2",
                            "isbn2",
                            LocalDateTime.of(2020, Month.DECEMBER, 14, 10, 50, 28),
                            LocalDateTime.of(2020, Month.DECEMBER, 14, 10, 50, 28),
                            "createdBy",
                            "modifiedBy")),
                    LocalDateTime.of(2020, Month.DECEMBER, 14, 10, 50, 28),
                    LocalDateTime.of(2020, Month.DECEMBER, 14, 10, 50, 28),
                    "createdBy",
                    "modifiedBy")));

    List<AuthorDto> result = authorService.findByOrgCode("orgCode");
    Assertions.assertEquals(
        Arrays.asList(
            new AuthorDto(
                Long.valueOf(1),
                "orgCode",
                "firstName",
                "lastName",
                new GregorianCalendar(2020, Calendar.DECEMBER, 14, 10, 50).getTime(),
                "email",
                Arrays.asList(
                    new BookDto(Long.valueOf(1), "book Name 1", "isbn1"),
                    new BookDto(Long.valueOf(2), "book Name 2", "isbn2")))),
        result);
  }

Now let see how we can use magical position using podam.

  @Test
  void testFindByOrgCode() {
    PodamFactory factory = new PodamFactoryImpl();
    List<AuthorDoc> authorDocs = factory.manufacturePojo(ArrayList.class, AuthorDoc.class);
    when(authorRepository.findByOrgCode(anyString())).thenReturn(authorDocs);

    List<AuthorDto> result = authorService.findByOrgCode("orgCode");
    Assertions.assertEquals(authorDocs.size(), result.size());
  }

How many code lines we saved???

Map(String, Pojo) using podom

Same like the above example, we can quickly build a map of date using podam.

  @Test
  void testFindAuthorMap() {
    PodamFactory factory = new PodamFactoryImpl();
    Map<String, AuthorDoc> authorDocMap =
        factory.manufacturePojo(HashMap.class, String.class, AuthorDoc.class);
    when(authorRepository.findMapByOrgCode(anyString())).thenReturn(authorDocMap);

    Map<String, AuthorDto> result = authorService.findAuthorMap("orgCode");
    result.forEach(
        (key, value) ->
            Assertions.assertEquals(authorDocMap.get(key).getUserId(), value.getUserId()));
  }

Defining an attribute-level strategy

So far, we see podam assign sample values to our POJO attributes. What happened if there is a validation. For example, if its an Email field we have to give an exact email address.

for that, we can use data strategies at the attribute level

Lets create a EmailStrategy class

public class EmailStrategy implements AttributeStrategy<String> {

    @Override
    public String getValue(Class<?> attrType, List<Annotation> attrAnnotations) {
        return "aaa.bbb@ccc.ddd";
    }
}

we can use this in 2 ways,

  1. use as attribute-level annotation
    @PodamStrategyValue(EmailStrategy.class)
    private String email;

2. config strategy when we create PadomFactory. then it will auto-assign POJO level validations

    PodamFactory factory = new PodamFactoryImpl();
    Class<? extends Annotation> annotation = Email.class;
    AttributeStrategy<?> strategy = new EmailStrategy();
    ((RandomDataProviderStrategy)factory.getStrategy()).addOrReplaceAttributeStrategy(annotation, strategy);

Limit collection size.

In our previous example, we have a list of books in the author object. Let’s see how we can limit the size of this list. For that, we can use @PodamCollection annotation.

  @PodamCollection(nbrElements = 3)
  private List<BookDoc> books;

We added collection elements size as 3. so this will only create 3 records of book attribute on that list.

For a full list of supported annotations, please refer to the podam Annotations page.

Conclusion

Thanks for reading the article Java Unit Tests make easy – Random Values with PODAM.

You can find source codes for this tutorial from our Github.