A lot of Java applications use System properties to hold their configuration. It’s very convenient especially for webapps, because you can set these properties from the server’s admin console.

Naturally, somewhere in the code, the properties are checked and a decision is made based on them. The question is: how can that code be well unit-tested?

The Egg and Jerry
Tom & Jerry - The Egg and Jerry, by William Hanna and Joseph Barbera

Take the following class:

public class Foo {
  public boolean act() {
    if("blue".equals(System.getProperty("color")) {
      return true;
    } else {
      return false;
    }
  }
}

And its corresponding test class:

public class FooTest {
  @Test
  public void actsWithBlue() {
    System.setProperty("color", "blue");
    assertTrue(new Foo().act());
  }

  @Test
  public void actsWithoutBlue() {
    System.setProperty("color", "green");
    assertFalse(new Foo().act());
  }

  @After
  public void clean(){
    System.clearProperty("color");
  }
}

Do these tests run fine? Yes. Do they leave the property wrongly initialized? No, the @After method runs even if a test throws an exception. So where’s the problem?

The problem occurs when you enable multi-threaded test runs. In that scenario the tests are run in parallel, not sequentially, which means that actsWithBlue() could initialize the “color” property before actsWithoutBlue() finishes execution, or vice-versa. Also, if other tests (for other classes) happen to work with real Foo objects instead of mocks, they will be in trouble as well.

I hope it’s clear that no test should set system properties, under any circumstances. Let’s introduce interface Color:

public interface Color {
  public String read();

  static class Fake implements Color {
    private String color;
    public Fake(String color) {
      this.color = color;
    }
    public String read() {
      return this.color;
    }
  }
}

and the real implementation:

public class SystemColor implements Color {
  public String read() {
    return System.getProperty("color");
  }
}

The Foo class becomes:

public class Foo {
  private Color color;
  public Foo(Color clr) {
    this.color = clr;
  }
  public boolean act() {
    if("blue".equals(this.color.read()) {
      return true;
    } else {
      return false;
    }
  }
}

It can now be properly tested using Color.Fake:

public class FooTest {
  @Test
  public void actsWithBlue() {
    assertTrue(
      new Foo(
        new Color.Fake("blue")
      ).act()
    );
  }

  @Test
  public void actsWithoutBlue() {
    assertFalse(
      new Foo(
        new Color.Fake("green")
      ).act()
    );
  }
}

Done. Now the tests don’t have to set any system property and can run in parallel without affecting one another. By the way, I used a “fake” implementation of Color instead of Mockito or other frameworks. I like to do that, if the interfaces are small - then it really makes no sense to bring in all the weight of an entire mocking framework.

Finally, if you’re wondering how to unit test SystemColor.read(), I can only tell you that that’s the kind of code due to which coverage is never 100%. And, after all, I think we can safely assume that System.getProperty(...) (being a part of the jdk) runs ok.

How does your app read system properties?