Javaでテストコードを書きたい

# テストコードの記述を毎回サボってしまう自分へ
レベルの低い内容となりますが、戒めとして記事にします。
内容についてはchatGPT様にまとめてもらい自分の感想をコメントとして残す。

## テストコードとは
テストコードは、ソフトウェアの動作が正しいことを確認するためのプログラムであり、
アプリケーションやその部品（関数やメソッド）が期待通りに動作するかを自動的に検証するために作成する。

本記事では単体テスト(Unit Test)を行うテストコードを例に記述

テストコードは主に以下の目的で使用：
- ソフトウェアの品質向上
- バグの早期発見
- 変更やリファクタリングの影響を検証


## テストコードの利点
1. バグの早期発見
   - テストコードを実行することで、開発中にバグを早期に見つけることが可能
   **→テストコードを書く「行為」がバグの発見に寄与するように感じてます**

2. リファクタリングの安心感
   - テストコードがあることで、既存の機能が壊れていないかを簡単に確認でき、安心してリファクタリングが可能です。
   **→自分が一番メリットに感じているポイントでリファクタリングに限らず、既存機能を改修する際にテストコードがすべて通ることは安心材料になります**

3. ドキュメントの代替
   - テストコードはコードの使い方や仕様を示す一種のドキュメントとして機能します。
   →クラス単体で仕様を把握できれば良いよりですが、テストコードも合わせてみると理解の速度が違いますよね

4. 開発効率の向上
   - 手動でテストを行う手間が省けるため、開発効率が向上します。
   **→顧客にテストコードの有用性について説明して工数をもらうのは容易じゃない気がしますが...
また、プロジェクトメンバにもメリットや考え方を根付かせて、プロジェクト全体で風土化する必要があると感じました。**
  
5. 継続的インテグレーション（CI）の基盤
   - テストコードはCI/CD環境で自動テストとして実行され、開発プロセス全体を効率化します。
　 **→CIを実際に組んでいるプロジェクトがどれほどあるのかが気になりました（経験上1プロジェクトのみ...）**


## JUnitを使ったテストコードの例
以下は、テスト対象のコードです。この `Calculator` クラスは基本的な算術演算を提供します。

```java
package calc;

public class Calculator {

    public int addition(int a, int b) {
        return a + b;
    }

    public int subtraction(int a, int b) {
        return a - b;
    }

    public int multiplication(int a, int b) {
        return a * b;
    }

    public double division(int a, int b) {
        if (b == 0) {
            throw new IllegalArgumentException("0で除算されました！");
        }
        return (double) a / b;
    }
}
```

次に、JUnit 5を使用してこのクラスの動作を確認するためのテストコードを示します。

以下は、JavaでJUnit 5を使用してテストコードを書く方法の例です。

```java
package calc;

import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;

public class CalculatorTest {

    @Test
    public void testAddition() {
        Calculator calculator = new Calculator();
        int result = calculator.addition(5, 3);
        assertEquals(8, result);
    }

    @Test
    public void testSubtraction() {
        Calculator calculator = new Calculator();
        int result = calculator.subtraction(5, 3);
        assertEquals(2, result);
    }

    @Test
    public void testMultiplication() {
        Calculator calculator = new Calculator();
        int result = calculator.multiplication(5, 3);
        assertEquals(15, result);
    }

    @Test
    public void testDivision() {
        Calculator calculator = new Calculator();
        double result = calculator.division(10, 2);
        assertEquals(5.0, result);
    }

    @Test
    public void testDivisionByZero() {
        Calculator calculator = new Calculator();
        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
            calculator.division(5, 0);
        });
        assertEquals("0で除算されました！", exception.getMessage());
    }
}
```

このコードでは、`Calculator` クラスの各メソッドをテストしています。`assertEquals` を使って期待値と実際の結果を比較し、例外が正しくスローされるかどうかも確認しています。

**→実際はここまでシンプルなクラスは珍しく、他のクラスに依存していることも多くモックを駆使しながらテストを行う**


## テストコード作成時のポイント
1. 単一のテストは一つの目的に集中する
   - テストメソッドは、基本的に一つの振る舞いを検証するように設計します。

2. 分かりやすい命名
   - テストメソッドや変数には、何をテストしているのかが分かる名前を付けましょう。
   **→英語が不得意なのでいっつも命名は迷います**

3. 自動化の徹底
   - テストは可能な限り自動で実行できるように設計します。

4. 失敗時に何が間違っているか分かるようにする
   - エラーメッセージやアサーションの使い方を工夫し、失敗時に原因が特定しやすいテストを心がけます。
   **→重要度高いように感じた。ここを適当に行うとテストコードの効力が発揮できないはず。
    誰が見てもどういう事象でテストに失敗したかが明確に分かるようにコードを書くこと**


## 個人的感想まとめ
上記の通りテストコードを書く際の備忘とする。
プロジェクトに導入する際はいくつもの障壁（工数の捻出、プロジェクトメンバの理解度 etc...）があるように感じるが、それを突破して導入するだけの価値を感じています。