LoginSignup
18
11

More than 3 years have passed since last update.

【Java】標準入力&標準出力をJUnitでテストしたい

Posted at

きっかけ

最近競技プログラミングの勉強をはじめた。ローカルで動作確認をする際にいちいち入力するのがめんどくさい。JUnitでやりたい。

環境

  • Windows10
  • IntelliJ IDEA Community Edition 2019.1.1
  • Java 1.8.0_211

参考にした記事

Qiita - JUnitで標準入力をつっこんで流す
kencobaの日記 - 標準入出力を横取りする
にょきにょきブログ - System.out を置き換えよう

概要

SystemクラスのsetOutsetInで出力先と入力先を標準出力、入力から変えることができる。
OutにはPrintStream、InにはInputStreamを継承したクラスを定義して設定すればよい。

実装

入力クラスと出力クラスを作成する。

入力クラス - StandardInputStream

StandardInputStream.java
import java.io.InputStream;

public class StandardInputStream extends InputStream {
    private StringBuilder sb = new StringBuilder();
    private String lf = System.getProperty("line.separator");

    /**
     * 文字列を入力する。改行は自動的に行う
     * @param str 入力文字列
     */
    public void inputln(String str){
        sb.append(str).append(lf);
    }

    @Override
    public int read() {
        if (sb.length() == 0) return -1;
        int result = sb.charAt(0);
        sb.deleteCharAt(0);
        return result;
    }
}

出力クラス - StandardOutputStream

StandardOutputStream.java
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.io.StringReader;

public class StandardOutputStream extends PrintStream {
    private BufferedReader br = new BufferedReader(new StringReader(""));

    public StandardOutputStream() {
        super(new ByteArrayOutputStream());
    }

    /**
     * 1行分の文字列を読み込む
     * @return 改行を含まない文字。終端の場合はnull
     */
    public String readLine() {
        String line = "";
        try {
            if ((line = br.readLine()) != null) return line;
            br = new BufferedReader(new StringReader(out.toString()));
            ((ByteArrayOutputStream) out).reset();
            return br.readLine();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

テスト対象コード

テスト対象コードはatcoderさんから拝借。
PracticeA - Welcome to AtCoder

問題
整数 a,b,cと、文字列 s が与えられます。 a+b+c の計算結果と、文字列 s を並べて表示しなさい。

入力

a
b c
s
WelcomeToAtCoder.java
import java.util.Scanner;

public class WelcomeToAtCoder {
    public static void main(String[] args) {
        try (Scanner sc = new Scanner(System.in)) {
            int r = sc.nextInt();
            r += sc.nextInt();
            r += sc.nextInt();
            String s = sc.next();
            System.out.println(r + " " + s);
        }
    }
}

テストコード

WelcomeToAtCoderTest.java
import WelcomeToAtCoder;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import util.io.StandardInputStream;
import util.io.StandardOutputStream;

import static org.hamcrest.CoreMatchers.is;

public class WelcomeToAtCoderTest {

    private StandardInputStream in = new StandardInputStream();
    private StandardOutputStream out = new StandardOutputStream();

    @Before
    public void before() {
        System.setIn(in);
        System.setOut(out);
    }

    @After
    public void after() {
        System.setIn(null);
        System.setOut(null);
    }

    @Test
    public void main01() {
        in.inputln("1");
        in.inputln("2 3");
        in.inputln("hoge");
        WelcomeToAtCoder.main(null);
        Assert.assertThat(out.readLine(), is("6 hoge"));
    }
}

事前処理で入出力を切り替えてテストする。

おわりに

テストケースを書くのは簡単なので実装が楽になった気がする。
これに限らずテストはちゃんと書こうと思った。
TDD勉強したいなあ。
JUnit久しぶりにさわった

18
11
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
11