💻

標準入力/標準出力をテストする

に公開

何をしたいか

極稀に、標準入力で何が入力されたか・標準出力で何が出力されたかをテストしたいことがあります。

やり方を備忘録としてメモしておきます。

環境

  • JDK 21
  • JUnit 5.12.2

多少バージョンが違っていても大丈夫だと思います。たぶん。

テスト対象

Sample1.java
public class Sample1 {
    public List<Integer> input() {
        Scanner scanner = new Scanner(System.in);
        System.out.print("整数を指定してください(複数の場合は半角スペース区切り、最後は半角スペース+a) -> ");
        ArrayList<Integer> idList = new ArrayList<>();
        for (int id; scanner.hasNextInt(); ) {
            id = scanner.nextInt();
            idList.add(id);
        }
        return idList;
    }
}
Sample2.java
public class Sample2 {
    public void output(String message) {
        System.out.println(message);
    }
}

標準入力のテスト

Javaの標準入力 System.injava.io.InputStream 型です。

テスト時は、これを java.io.ByteArrayInputStream ( java.io.InputStream のサブクラス)に差し替えます。

System.in は staticフィールドなので、差し替えたままだと他の箇所にも影響が出てしまいます。テスト終了後は元の InputStream に戻します。

Sample1Test.java
public class Sample1Test {
    Sample1 sample1 = new Sample1();

    // 標準入力を元に戻すために保存しておく
    InputStream originalIn = System.in;

    @AfterEach
    void afterEach() {
        // テスト後、標準入力を元に戻す
        System.setIn(originalIn);
    }

    @Nested
    @DisplayName("input()")
    class Input {
        @Test
        @DisplayName("標準入力から「1 2 3」が入力されると、リスト[1, 2, 3]を取得できる")
        void success() {
            // 差し替え
            ByteArrayInputStream bais = new ByteArrayInputStream("1 2 3".getBytes(StandardCharsets.UTF_8));
            System.setIn(bais);
            // 実行
            List<Integer> actual = sample1.input();
            // 検証
            assertEquals(List.of(1, 2, 3), actual);
        }
    }
}

標準出力

Javaの標準出力 System.outjava.io.PrintStream 型です。

PrintStream のコンストラクタjava.io.OutputStreambooleanjava.nio.charset.Charset を引数で受け取ります。

テスト時は、コンストラクタに java.io.ByteArrayOutputStream ( OutputStream のサブクラス)を指定した PrintStream に差し替えます。

System.out は staticフィールドなので、差し替えたままだと他の箇所にも影響が出てしまいます。テスト終了後は元の PrintStream に戻します。

Sample2Test.java
public class Sample2Test {
    Sample2 sample2 = new Sample2();

    // 標準出力を元に戻すために保存しておく
    PrintStream originalOut = System.out;

    @AfterEach
    void afterEach() {
        // テスト後、標準出力を元に戻す
        System.setOut(originalOut);
    }

    @Nested
    @DisplayName("output()")
    class Output {
        @Test
        @DisplayName("指定した文字列が、改行付きで標準出力に出力される")
        void success() {
            // 差し替え
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            PrintStream ps = new PrintStream(baos, true, StandardCharsets.UTF_8);
            System.setOut(ps);
            // 実行
            sample2.output("Hello!");
            // 検証
            assertEquals("Hello!" + System.lineSeparator(), baos.toString(StandardCharsets.UTF_8));
        }
    }
}

Discussion