Junit4 の framework で 複数テストを行う

## Junit4 の framework で遊んでみた

[このレポジトリ](https://github.com/junit-team/junit4/tree/main/src/main/java/junit/framework) に、Junit3 ライクなテストライブラリが入っている。しかし、このライブラリでは複数テストの実行は行えなさそうなので、それを実現してみた（tearDown や setUp関数のような関数を見れば、カスタマイズ向けなライブラリな感じもしなくはないが・・・）。

ここでは、test から始まるメソッドでテストを複数個行えるようにコードの改造を行なった。以下のコードが動くようになるのが目標。

```diff_java
import junit.framework.Assert;
import junit.framework.TestCase;
import junit.framework.TestResult;

public class Sample {

	public static class MathTest extends TestCase {
		protected double fValue1;
		protected double fValue2;

		public MathTest(String fName) {
			super(fName);
		}

		public MathTest() {
			super();
		}

		@Override
		protected void setUp() {
			fValue1 = 2.0;
			fValue2 = 3.0;
		}

+		public void testAdd() {
+			double result = fValue1 + fValue2;
+			assertTrue(result == 5.0);
+		}
+
+		public void testAddFail() {
+			double result = fValue1 + fValue2;
+			assertTrue(result == 5.0);
+		}
+	}

	public static void main(String[] args) {
		TestCase test = new MathTest();
		TestResult testResult = test.run();
		System.out.println(testResult.toString());
	}
}
```

まずコードを変えるのは、[TestCase.java](https://github.com/junit-team/junit4/blob/main/src/main/java/junit/framework/TestCase.java) の テストを数えるコード。testMethods という `ArrayList<Method>` を用意して、`countTestCases` ではそのサイズを取得するようにコードを変える（該当箇所は[ここ](https://github.com/junit-team/junit4/blob/80838a508b8875080c1b59d04f14ebaf74908af0/src/main/java/junit/framework/TestCase.java#L101-L103)）。

```java
    public int countTestCases() {
        // return 1;
        return testMethods.size();
    }
```

この testMethods を 初期化する関数を用意する。

```java
    /*
     * Initialize test cases
     */
    private void initTestMethods() {
        Method[] originalMethods = getClass().getMethods();
        for (int i = 0; i < originalMethods.length; i++) {
            Method selectedMethod = originalMethods[i];
            String selectedMethodName = selectedMethod.getName();
            if (selectedMethodName.startsWith("test")) {
                testMethods.add(selectedMethod);
            }
        }
    }
```

簡単に言えば、クラスが保持しているメソッド一覧を取得して、それが `test` から始まる文字列であったら、それを testMethods の配列に追加するようにしている。
この initTestMethods を `run` で呼び出す（該当箇所は[ここ](https://github.com/junit-team/junit4/blob/80838a508b8875080c1b59d04f14ebaf74908af0/src/main/java/junit/framework/TestCase.java#L129-L131)）。

```java
    /**
     * Runs the test case and collects the results in TestResult.
     */
    public void run(TestResult result) {
        initTestMethods();
        result.run(this);
    }
```

そして、最後に method を invoke している部分で新しい関数を作ります。

```java
    protected void runTests() throws Throwable {
        for (int j = 0; j < testMethods.size(); j++) {
            try {
                testMethods.get(j).invoke(this);
            } catch (InvocationTargetException e) {
                e.fillInStackTrace();
                throw e.getTargetException();
            } catch (IllegalAccessException e) {
                e.fillInStackTrace();
                throw e;
            }
        }
    }
```

[runBare](https://github.com/junit-team/junit4/blob/80838a508b8875080c1b59d04f14ebaf74908af0/src/main/java/junit/framework/TestCase.java#L138-L153) 内で、この runTests を runTest の代わりに呼び出します。

```diff_java
    public void runBare() throws Throwable {
        Throwable exception = null;
        setUp();
        try {
+            runTests();
-            // runTest();
        } catch (Throwable running) {
            exception = running;
        } finally {
            try {
                tearDown();
            } catch (Throwable tearingDown) {
                if (exception == null) exception = tearingDown;
            }
        }
        if (exception != null) throw exception;
    }
```

これで test から始まるメソッドで、複数のテストが行えるようになりました。

## 最後に

ここのコードをチラッと見たのが参考になりました。
ありがとうございました。

https://github.com/ToruTakefusa/MyJUnit