How do you write "Production Code" for UnitTest?
Tags: testing, java, beginners
Published: 2018-09-30 22:48:53

---
title: How do you write "Production Code" for UnitTest?
published: true
? description
tags: testing, java, beginners
---

## Introduction

UnitTest is very important for keeping code quality.
So almost project require to write UnitTest.

As a result, I will review strange UnitTest or I will be asked them about "I can't write UnitTest!".

Why? Because they don't consider about production code for UnitTest.
They only consider about UnitTest code for UnitTest. This is not good.

We should divid "business logic" and "uncontrolled value" from production code for writing UnitTest. This is also good for "readability".

Basic rule is only two.

- Sepalate "business logic" and "uncontrolled value like a I/O, date, random"
- Inject dependency by argument, constructer, non-private fields

In this article, I explain how do you write production code for UnitTest.

## Typically example

Firstly, I explain typically cases.

### Case 01: "I want to output to standard output"

You should sepalate the logic and the output method like a `System.out.println` or `Logger.info`.
You make a simple method for building "output string".

```java
// Production Code:

public class Example01Good {
    public static void main(String[] args) {
        String message = args[0];
        System.out.println(makeMessage(message));
    }

    static String makeMessage(String message) {
        return "Hello, " + message;
    }
}
```

```java
// UnitTest Code:

@Test
public void testMakeMessage() {
    assertThat(Example01Good.makeMessage("world"), is("Hello, world"));
}
```

### Case 02: "I want to use random number"

Random number is not able to fix result.
So we need to sepalate the logic and the number generator.
This is a simple dice game logic for checking "Odd" or "Even"

```java
// Production Code:

public class Example02Good {
    public static void main(String[] args) {
        System.out.println(check(throwDice(Math.random())));
    }

    static String check(int num) {
        return (num % 2 == 0) ? "Win" : "Lose";
    }

    static int throwDice(double rand) {
        return (int) (rand * 6);
    }
}
```

```java
// Test Code:

@Test
public void testCheck() {
    assertThat(Example02Good.check(1), is("Lose"));
    assertThat(Example02Good.check(2), is("Win"));
    assertThat(Example02Good.check(3), is("Lose"));
    assertThat(Example02Good.check(4), is("Win"));
    assertThat(Example02Good.check(5), is("Lose"));
    assertThat(Example02Good.check(6), is("Win"));
}
```

### Case 03: "I want to calcurate calendar like tomorrow, 1 year ago or later"

Calculating calendar is very general code. But `current time` like `today` is uncontrolled value.
You need to sepalate the calendar Calculation logic and getting `current time`.

You can use `method arguments` like a random number. This is good pracitice.
But sometimes `getting current time` is used on many places. In such a case, you can also use `factory pattern`.

```java
// Production Code

class SystemDate {
    public LocalDate today() {
        return LocalDate.now();
    }
}

public class Example03Good {
    SystemDate systemDate = new SystemDate();

    public LocalDate tomorrow2() {
        return systemDate.today().plusDays(1);
    }
}
```

```java
// Test Code

@Test
public void testTomorrow2() {
    Example03Good target = new Example03Good();
    target.systemDate = new SystemDate() {
        @Override
        public LocalDate today() {
            return LocalDate.of(2017, 1, 16);
        }
    };
    assertThat(target.tomorrow2(), is(LocalDate.of(2017, 1, 17)));
}
```

### Case 04: "I want to manage File I/O"

Basically, this is same with Standard I/O case. You should sepalate the logic for `building Text or Binary` and the logic for read or write.
This is pretiy good.

But sometimes you need very many text size, checking line order and so on.
In such a case, you can use Reader/Writer and InputStream/OutputStream to sepalate logic and I/O.

```java
// Production Code

public class Example04Good {
    public static void main(String[] args) throws Exception {
        System.out.println("hello");
        try (Reader reader = Files.newBufferedReader(Paths.get("intput.txt"));
                Writer writer = Files.newBufferedWriter(Paths.get("output.txt"));) {
            addLineNumber(reader, writer);
        }
    }

    static void addLineNumber(Reader reader, Writer writer) throws IOException {
        try (BufferedReader br = new BufferedReader(reader);
                PrintWriter pw = new PrintWriter(writer);) {
            int i = 1;
            for (String line = br.readLine(); line != null; line = br.readLine()) {
                pw.println(i + ": " + line);
                i += 1;
            }
        }
    }
}
```

```java
// Test Code

@Test
public void testAddLineNumber() throws Exception {
    Writer writer = new StringWriter();
    addLineNumber(new StringReader("a\nb\nc\n"), writer);
    writer.flush();
    String[] actuals = writer.toString().split(System.lineSeparator());

    assertThat(actuals.length, is(3));
    assertThat(actuals[0], is("1: a"));
    assertThat(actuals[1], is("2: b"));
    assertThat(actuals[2], is("3: c"));
}
```

## Fundamental Concept

In this section, I explain more deeply.

### Sepalate logic and I/O

Most importantly, you should seplate logic and I/O every time.
This is important desigin for UnitTest.

Let's take an example of a simple program for "getting text from command line arguments and print out to standard out".

```java
public class Example01Bad {
    public static void main(String[] args) {
        String message = args[0];
//         String message = "World"; // for debug.
        System.out.println("Hello, " + message);
    }
}
```

Maybe, this is the most simple code. I beleave you write down same code firstly.
`for debug` comment is funny.

Next, let's write UnitTest.

```java
/**
 * Super bad code
 */
@Test
public void testMain() {
    String[] args = {"world"};
    Example01Bad.main(args);
}
```

This is a super simple. But there is NO assertion! So this UnitTest require to check True or False by your eyes!
Do you think this is a joke? Unfortunatly, I see such a UnitTest on real project again and again...

Of cource this code is terrible. More better people write blow code.

```java
/**
 * Bad code
 */
@Test
public void testMainWithSystemOut() {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    System.setOut(new PrintStream(out));

    String[] args = {"world"};
    Example01Bad.main(args);

    assertThat(out.toString(), is("Hello, world" + System.lineSeparator()));
}
```

This code hook StandardOut. It is not bad.
You can run it as UnitTest perfectly. But it's complex jsut a little.

If you can't modify target production code, you should write it.
However if you can change production code, UnitTest becomes more easily.

```java
// Good production code
public class Example01Good {
    public static void main(String[] args) {
        String message = args[0];
        System.out.println(makeMessage(message));
    }

    static String makeMessage(String message) {
        return "Hello, " + message;
    }
}
```

I sepalate "building message logic" as makeMessage method. So UnitTest becomes following.

```java
// Good test code
@Test
public void testMakeMessage() {
    assertThat(Example01Good.makeMessage("world"), is("Hello, world"));
}
```

This is a very simple. And it's perfect as UnitTest.

You might think it strange, because this code doesn't do any test about StandardOut.
Exactly. But it's not necessary as UnitTest.

Basically, Checking bussiness logic is the most impotantly in UnitTest.
`Sysmte.out.println` and Logging library is standard or popular library.
That means their code quality is keeped by other tests. You are only careful about your business logcic.
Of course, you also need to check about Standard Output and so on. But it is integration test.

### Don't initilze uncontrolled values directly

You should not initialize uncontrolled value like a randome number, date, RPC(WebAPI), DAO on your each method.
Please apply the concept of DI(Dependency Injection).

Let's take an example of a method for `calculating tomorrow`.

```java
public class Example03Bad {
    public LocalDate tomorrow() {
        return LocalDate.now().plusDays(1);
    }
}
```

Naturally, this code is not able to do UnitTest. Because `LocalDate.now()` value changes every time.
So `LocalDate.now()` is uncontrolled value. This is a typical beginner's trap.
You need to sepalate it from business logic. The most simple solution is to use method arguments.

```java
public LocalDate tomorrow(LocalDate today) {
    return today.plusDays(1);
}
```

So you can fix test code follwing.

```java
@Test
public void testTomorrow() {
    Example03Good target = new Example03Good();
    assertThat(target.tomorrow(LocalDate.of(2017, 1, 16)), is(LocalDate.of(2017, 1, 17)));
}
```

This is enough. But if getting current time is used on many places, you can also factory method pattern and stub.
Firstly, you make factory class which has a method `today()` to return `LocalDate`.
Next, you set it on target code field.

Return value of `today()` is depends on implementation. In production, it is `LocalDate.now()`.

```java
class SystemDate {
    public LocalDate today() {
        return LocalDate.now();
    }
}

public class Example03Good {
    SystemDate systemDate = new SystemDate();

    public LocalDate tomorrow2() {
        return systemDate.today().plusDays(1);
    }
}
```

In test code, you use stub instead of `LocalDate.now()`.

```java
@Test
public void testTomorrow2() {
    Example03Good target = new Example03Good();
    target.systemDate = new SystemDate() {
        @Override
        public LocalDate today() {
            return LocalDate.of(2017, 1, 16);
        }
    };
    assertThat(target.tomorrow2(), is(LocalDate.of(2017, 1, 17)));
}
```

The key is to use `package scope` instead of `private scope` or you should initialize by constructor.
If you use private scope, you need a mock framework and so on.

Summary
--------

Basic rule is only two.

- Sepalate "business logic" and "uncontrolled value like a I/O, date, random"
- Inject dependency by argument, constructer, non-private fields

This is not difficult. But sometimes biginner doesn't know it.
In addtion, TDD(Test Driven Development) and Test First force you to write such code.
It is a reasn that TDD is populer. 

And functional language is more strict style about side effect. Let's try to study also it.