Why test POJOs?
Tags: java, testing
Published: 2019-05-12 14:38:11

---
title: Why test POJOs?
published: true
description: Developers disagree on whether unit tests should be written for POJOs. Here's one big reason why you should.
tags: java, testing
cover_image: https://thepracticaldev.s3.amazonaws.com/i/l09dkpspx3embjm0z4vt.jpg
---

Photo by [Louis Reed on Unsplash](https://unsplash.com/photos/pwcKF7L4-no?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)

[POJOs (Plain Old Java Objects)](https://en.wikipedia.org/wiki/Plain_old_Java_object) and their ilk such as [value objects](https://en.wikipedia.org/wiki/Value_object) and [JavaBeans](https://en.wikipedia.org/wiki/JavaBeans) occupy a unique place in modern Java applications. They have hundreds of slightly different use cases. They are often serialized and deserialized into JSON, XML, or SQL. They form the bridges between layers in complex applications. They represent the domain specific language.

And they are often untested.

The argument against testing them is usually based on the assumption that POJOs have state but no behavior. A POJO is usually just a bag of data with getters and sometimes setters. If you've ever seen a unit test for the typical POJO getter&mdash;the kind that directly returns a variable&mdash;it seems rather pointless. Why test that the language does what the language does?

The idea of testing such a getter doesn't pass even the simplest test of the most ardent test-driven advocate. In a [Stack Overflow answer](https://stackoverflow.com/questions/674408/junit-tests-for-pojos), [Robert C. Martin](https://en.wikipedia.org/wiki/Robert_C._Martin) says:

> My personal rule is that I'll write a test for any function that makes a decision, or makes more than a trivial calculation. I won't write a test for i+1, but I probably will for if (i<0)... and definitely will for (-b + Math.sqrt(b*b - 4*a*c))/(2*a).

And that's certainly a fair point. I'd wager that the majority of people _actually_ avoid testing POJOs for another reason (because its tedious), but I guess it's nice to know that there's at least one solid argument to support developer laziness.

I'd like to examine the question from another context, though, one which I think changes everything: object-oriented design.

## Decoupling and The Uniform Access Principle
Let's start with the [Uniform Access Principle](https://en.wikipedia.org/wiki/Uniform_access_principle) (UAP). Largely forgotten in today's world, the UAP states that:

> All services offered by a module should be available through a uniform notation, which does not betray whether they are implemented through storage or through computation

In Java terms, the UAP is asking, "when you call a getter (service) on a class (module), is the value received just a piece of data or is it computed (or derived) from other data?"

Client code isn't supposed to know. 

_So what?_ you might ask. _We all know that POJOs are just some wrappers around data. Why pretend otherwise?_

Well, the UAP (somewhat pedantically) points out that client code can't make that assumption. If a module betrays its implementation to client code, or client code makes assumptions about where the value came from, it violates fundamental OO design principles.

From that lens, you should even test getters. They may simply be returning a value, but what if they're not? Or, what if they are, but that changes in the future?

## The benefit of this mindset

One goal of OO is to decouple interface from implementation, making the implementation able to evolve without forcing change on collaborating code. In the early days of Java applications, this decoupling was carried out literally by creating an interface for every class. This explicit physical separation (two separate files) underlined the idea that the current class was only one possible implementation of the interface among potentially many.

Thinking fourth-dimensionally, the "potentially many" implementations also may include the different evolutions of that same POJO over an application's lifecycle.

So the benefit of viewing an application in the context of interfaces is that we maximize its extensibility. With interfaces as the units of application design, we can evolve any given part of the application that needs to change without imposing those changes to any collaborating classes. They are decoupled from the implementation. The interface acts as a fence around change. As long as the _interface_ doesn't change, collaborators don't need to either.

In practical terms, that means we can "move fast" in reaction to changes in user demands and/or the business environment.

## The purpose of tests
OK, how is that relevant to testing? Well, moving fast is possible only when developers can quickly and safely evolve implementations. So I believe that, along with the compiler, tests should provide that safety. Tests should guarantee that implementations adhere to the interface they advertise.

When I say "interface" in this context I'm not talking only about Java's [interface](https://docs.oracle.com/javase/tutorial/java/IandI/createinterface.html) keyword, but the [OO term](https://stackoverflow.com/questions/2866987/what-is-the-definition-of-interface-in-object-oriented-programming#2867064). Do the methods exposed by a class behave as the client expects? If the return type is an object, what does null mean? If a primitive, are there certain values like -1 which indicate that something doesn't exist? What validation does or doesn't happen to input that's passed in? What is required from that input?

Basically, think of tests as one way to insure [method contracts](https://en.wikipedia.org/wiki/Design_by_contract). In modern Java, tests are the best way to do that. Tests provide a verification of the method contract that the compiler cannot. We don't want to test that the language does what the language does (the compiler already does that), but there are still other things we need to know.

## Practical examples
This is not just theoretical. It comes up all the time. Here are some examples.

### Agreement between constructor or setters and getters
Even though a POJO is a "dumb object" it is still expected that after construction an object's getters return the value the object was instantiated with. And if it's a mutable object (which you should avoid but that's probably a conversation for another time) then after you call a setter, a call to its corresponding getter should return the new value.

The fact that so many POJOs or POJO parts are created by copy-and-paste makes this not so much of a sure thing. It's pretty easy for two getters, let's say `getFirstName` and `getLastName` to get fat-fingered by fallible humans as follows:

```java
public String getFirstName() {
  return firstName;
}

public String getLastName() {
  return firstName; // ack!
}
```

Will the compiler catch that? Nope. Will a hurried developer? Sometimes? Will a good unit test? Yes.

### Insuring the meaning of data
Even "dumb" data can have a contract. I alluded to this earlier when I asked, "if this is an object, what is the meaning of null?" There are all kinds of situations where data has special values like null, -1, a value from an enum, or something else. That's a whole lot of situations where tests should really help give us assurances that our application is working correctly. Another class of data-only problems arises out agreement between multiple data fields. For example, if I worked zero hours in a pay period, I can't still have worked overtime. Similarly, if there's any kind of validation in a given POJO, that should be tested. What if a getter returns an int but that int represents a percentage? Is it okay if that number is ever less than zero or greater than 100? How will that application's tests insure against developer mistakes?

And, by the way, a percentage returned from a getter is a great example where the UAP fully applies. A percentage is probably _computed_ from two other values, but who knows?

### Adding behavior where there once was none
Perhaps you're philosophically opposed to POJOs having behavior, but in a real life application it is sometimes better than the alternative. A classic example is refactoring to eliminate [feature envy](http://wiki.c2.com/?FeatureEnvySmell). Feature Envy is a famous code smell introduced by Martin Fowler in the book _Refactoring_ and it is also seen in the classic book _Clean Code_ by Robert C. Martin, where it appears as G14 in the _Smells and Heuristics_ chapter. There, the following example is given:

```java
public class HourlyPayCalculator {
  public Money calculateWeeklyPay(HourlyEmployee e) {
    int tenthRate = e.getTenthRate().getPennies();
    int tenthsWorked = e.getTenthsWorked();
    int straightTime = Math.min(400, tenthsWorked);
    int overTime = Math.max(0, tenthsWorked - straightTime);
    int straightPay = straightTime * tenthRate;
    int overtimePay = (int)Math.round(overtime*tenthRate*1.5);
    return new Money(straightPay + overtimePay);
  }
}
```

The following explanation of feature envy is given:

> The `calculateWeeklyPay` method reaches into the `HourlyEmployee` object to get the data on which it operates. The `calculateWeeklyPay` method _envies_ the scope of `HourlyEmployee`. It "wishes" that it could be inside `HourlyEmployee`.

Of course, the answer is to move `calculateWeeklyPay` into `HourlyEmployee`. Unfortunately, that is a problem if you have a codebase with a rule excluding `HourlyEmployee`'s package from testing and code coverage.

### Equality and identity
Final quick example. One of the main uses of POJOs is to give the application meaningful equality logic. But uses cases differ; do you want to check equality or identity? The main thing that defines a [value object](https://en.wikipedia.org/wiki/Value_object) is that it is equal to another value object when their respective members are all equal. But other types of POJOs probably need to be differentiated based on identity. Is it always obvious which are which? Do you trust your dev team (or yourself) to automatically know the difference and add or remove tests as things change. Should you provide tests to guarantee that behavior?

## What do you think?
I hope this at least shows the most ardent POJO-testing opponent that there are good reasons for testing them. Perhaps now you'll at least _add_ tests if any of these cases arise in your existing POJOS. What do you think? If you don't test POJOs right now, do you think you will start? Or do you test them already? If so, why? What are your reasons? Let me know your thoughts in the comments below.