きっかけ
最近競技プログラミングの勉強をはじめた。ローカルで動作確認をする際にいちいち入力するのがめんどくさい。JUnitでやりたい。
環境
- Windows10
- IntelliJ IDEA Community Edition 2019.1.1
- Java 1.8.0_211
参考にした記事
Qiita - JUnitで標準入力をつっこんで流す
kencobaの日記 - 標準入出力を横取りする
にょきにょきブログ - System.out を置き換えよう
概要
System
クラスのsetOut
、setIn
で出力先と入力先を標準出力、入力から変えることができる。
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
```java: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久しぶりにさわった