POJO and JavaBean testing using Bean-matchers

Last update: Jun 02, 2020

Project repo: https://github.com/gualtierotesta/blog-projects/tree/master/pojo-testing

The first reaction to the question “Should I unit test a data class?” is usually a big NO because there is no meaning to check a data class which contains boiler plate code (getter, setter, equals..) often generated by means of the IDE or by libraries like Lombok and Immutables.

Real world projects are, unfortunately, not so perfect and there are cases where unit testing a POJO or a JavaBean could make sense. Let me list some situations I have encountered.

1. Security sensitive fields

If the data class contains a security sensitive field like a password or an API token, this field should NOT be logged.

See what OWASP has to say about this problem: https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html#data-to-exclude

For this reason, the class should not include sensitive fields in the toString method.

2. Logging unfriendly fields

The data class can contain fields which are binary data or very long string. In this case, we should exclude these fields from the toString method to prevent them to bloat our logging files.

3. Non standard equals and hashCode methods

The standard way to implement an equals method is to compare, one by one, all fields in the class. Sometimes one field contains a “unique” identifier that makes other fields comparison useless or even dangerous.

For example, this field can contain the primary key column of the database record from which the POJO data has been extracted. In this case, the POJO equality could or should depend only on its primary key field and the equals (and hashCode) implementation should use just this field.

4. No args constructor (JavaBeans)

The JavaBean standard requires the presence of a no-args constructor, a constructor without parameters.

The compiler usually creates the no args constructor unless there are already other (non no-args ) constructors defined in the class.

At runtime, the library (for example, the JPA libraries) which rely on the no-args constructor presence will fail at runtime due to the missing no-args constructor.

One important remark: checking all above conditions using an unit test is a way to guarantee the correct behaviour of the data class along all project life. The class can be correctly implemented when created but, later, one developer, while adding a new field in the class, can wrongly regenerate the toString method, restoring the log of a password field, or forget to regenerate the equals/hashCode methods in the proper way.

Checking data class quality is also useful in legacy projects to detect improper classes definitions because unit class can be added aside the “main” classes, without disturbing the legacy code.

The Bean-matchers library

The Bean-matchers library, created by Orien Madgwick, let us test the class conditions to guarantee that all future changes in the class will not break them.

Project repo is at https://github.com/orien/bean-matchers

Let’s assume we have the following data class:

class BasicBean {
  private int id;
  private String string;
  private char[] password;
  private Long[] longArray;
  private String veryLongString;

  public LombokBean(final int id) {
    this.id = id;
  }

   // getter, setter, equals, hashCode, toString

Conditions we want to assure:

  1. the id field should be used to check equality and to generate the class hash
  2. the password field should not be logged because security sensible
  3. the veryLongString field should not be logged to avoid logging files bloating
  4. the class should have a no-args constructor to be used with JPA.

Using the Bean-matchers library, the test class can be:

@Test
public void testTheClassIsGoodJavaBean() {
  MatcherAssert.assertThat(BasicBean.class,
    CoreMatchers.allOf(
      // This is Java Bean so we want an empty constructor
      BeanMatchers.hasValidBeanConstructor(),
      // All fields should have getter and setter
      BeanMatchers.hasValidGettersAndSetters(),
      // Only the 'id' field in hashcode and equals
      BeanMatchers.hasValidBeanHashCodeFor("id"),
      BeanMatchers.hasValidBeanEqualsFor("id"),
      // Password and veryLongString fields should not 
      // be included in the toString method
      BeanMatchers.hasValidBeanToStringExcluding(
          "password", "veryLongString")
    ));
}

The Beans-matchers library create an instance of our BasicBean class and checks if all conditions we have defined on

  • the constructor
  • the getters and setters,
  • the equals method
  • the hashCode method
  • the toString method

are valid otherwise the test fails.

A test failure will alert us whenever a change in the BasicBean class breaks the above conditions. It is a kind of safety net.

For Lombok users

Using Lombok, we can implement our bean conditions using Lombok annotations. The following code is the equivalent version of the plain Java version reported above:

@Data
@NoArgsConstructor
@EqualsAndHashCode(of = "id")
@ToString(exclude = {"password", "veryLongString"})
public class LombokBean {
  private int id;
  private String string;
  private char[] password;
  private Long[] longArray;
  private String veryLongString;

  public LombokBean(final int id) {
    this.id = id;
  }
}

When using Lombok, I believe there is no need to have a unit test to check our bean conditions because, in general, we should not test third party libraries (Lombok in this case), but having it will not damage your project 😉

Final remarks

Another possible benefit of testing data classes, especially in legacy projects, is that their code coverage is easily 100%. This should not be the main purpose (remember, there is no meaning to test getter and setter) but a side effect which I’ve found useful: having the data classes at 100%, the low test coverage is due to the logic classes, the classes which contains the code which implement the application logic. They should be the main target of any test!

Unit testing Java data classes immutability with the Mutability Detector

Updated post can be found on my new blog site.

In all our project, we use data classes which, by definition, contain data (fields) but no (business) logic.

According to the best coding practices, a data class should preferably be immutable because immutability means thread safety. Main reference here is Joshua Bloch’s Effective Java book; this Yegor Bugayenko’s post is also very interesting reading.

An immutable class has several interesting properties:

  • it should be not sub-classable (i.e. it should be final or it should have a static factory method and a private constructor)
  • all fields should be private (to prevent direct access)
  • all fields should be written once (at instance creation time) (i.e. they should be final and without setters)
  • all mutable type (like java.util.Date) fields should be protected to prevent client write access by reference

An example of immutable class is the following:

public final class ImmutableBean {

private final String aStr;
private final int anInt;

public ImmutableBean(String aStr, int anInt) {
this.aStr = aStr;
this.anInt = anInt;
}

public String getAStr() {
return aStr;
}

public int getAnInt() {
return anInt;
}
}

Note: as frequent in Java, there is a lot of boilerplate code which hides the immutability definitions.

Libraries like Project Lombok makes our life easier because we can use the @Value annotation to easily define an immutable class as follows:

@Value
public class LombokImmutableBean {
String aStr;
int anInt;
}

which is a lot more more readable.

Should we (unit) test a class to check its immutability?

In a perfect world, the answer is no.

With the help of our preferred IDE automatic code generation features or with libraries like Lombok it is not difficult to add immutability to a class.

But in a real world, human errors can be happen, when we create the class or when we (or may be a junior member of the team) modify the class later on. What happen if a new field is added without final and a setter is generated by using IDE code generator? The class is no more immutable.

It is important to guarantee that the class is and remains immutable along all project lifetime.

And with the help of the Mutability Detector we can easily create a test to check the immutability status of a class.

As usual, Maven/Gradle dependencies can be found on Maven Central.

To test our ImmutableBean we can create the following jUnit test class:

import static org.mutabilitydetector.unittesting.MutabilityAssert.assertImmutable;

public class ImmutableBeanTest {

@Test
public void testClassIsImmutable() {
assertImmutable(ImmutableBean.class);
}
}

the test will fail if the class is not immutable.

For example, if a field is not final and it has a setter method, the test fails and the error message is very descriptive:

org.mutabilitydetector.unittesting.MutabilityAssertionError:
Expected: it.gualtierotesta.testsolutions.general.beans.ImmutableBean to be IMMUTABLE
but: it.gualtierotesta.testsolutions.general.beans.ImmutableBean is actually NOT_IMMUTABLE
Reasons:
Field is not final, if shared across threads the Java Memory Model will not guarantee it is initialised before it is read.
[Field: aStr, Class: it.gualtierotesta.testsolutions.general.beans.ImmutableBean]
Field [aStr] can be reassigned within method [setaStr]
[Field: aStr, Class: it.gualtierotesta.testsolutions.general.beans.ImmutableBean]

The complete project can be found on my Test Solutions gallery project on GitHub. See module general.

The approach I suggest is to use Lombok without any immutability test. If Lombok cannot be used (for example in a legacy project), use the Mutability Detector to assert that the class is really immutable.

Vaadin dependencies in Maven projects

Updated post can be found on my new blog site.

The Vaadin framework has several dependencies but not all of them should be included in our war/ear artifacts.

The following table shows all Vaadin version 7.6/7.7 main modules and their meaning and usage

Module Description and usage
server This is the core of the framework. It has the following (transitive) dependencies: vaadin-shared and vaadin-sass-compiler
themes Compiled version of the standard Vaadin themes
client-compiled Compiled version of the standard Vaadin widgets set
client Vaadin and GWT classes for widgets
client-compiler Widgets compiler based on GWT Google Web Toolkit
push Optional module. It includes the support for push protocols (server to client) thanks to the Atmosphere framework
shared Common modules code. It is included as dependency in the server module
sass-compiler SASS to CSS compiler, used at build time and at run-time (“on-the-fly” compilation). It is included as dependency in the server module

Depending on the project requirements, the above modules should be included or not as project dependencies. We can identify two possible scenarios:

  1. Project without a custom widget set. It can have a custom theme
  2. Project with a custom widget set

In the first case (without a custom widget set) we need the following modules:

  • server
  • themes
  • push (optional)
  • client-compiled

while, if we have a custom widget set, we need to compile the widgets so the dependencies become:

  • server
  • themes
  • push (optional)
  • client (for build only)
  • client-compiler (for build only)

Note: the compiled custom widgets are included in our artifact

The following table summarizes the Maven dependencies:

Module ArtifactId Scope Required?
server vaadin-server compile yes
themes vaadin-themes compile yes
client-compiled vaadin-client-compiled runtime only if the project does not use custom widget set
client vaadin-client provided only with custom widget set
client-compiler vaadin-client-compiler provided only with custom widget sett. See also note below.
push vaadin-push compile optional
shared vaadin-shared vaadin-server dependency. No need to be specified in the pom.xml
sass-compiler vaadin-sass-compiler vaadin-server dependency. No need to be specified in the pom.xml

Note: the vaadin-client-compiler dependency is automatically included in the classpath by the Vaadin Maven plugin (vaadin-maven-plugin) when the custom widgets set should be compiled.