2011-11-12 4 views
2

ユーザー入力用にSystem.inから読み取るクラスに対してテストを実行するにはどうすればよいですか?Javaで入力を読み込むユニットテストクラスは、どのようにして単体テストできますか?

例えば

:私は多分メインクラスをサブクラス化し、スクリプトの答えをフィードバックするgetUserInputをオーバーライドすると思ってきました

private int getUserInput() { 
    Scanner scanner = new Scanner(System.in); 

    System.out.print("What's ya input? [1-3]: "); 
    return scanner.nextInt(); 
} 

。入力を決定するためにSystem.outを読む必要がある場合、これは機能しませんが。

スレッドを検索するのに数時間を費やしましたが、これをどのように使用するかはわかりませんでした。

答えて

13

さて、あなたSystem.setIn()を使用してSystem.inを置き換えることができますが、私はそのアプローチを支持しません。グローバルな状態を設定しますあなたのテストは常に脆弱で不透明になります。

代わりに、本当にbたとえば、読み込みたいInputStreamをクラスのコンストラクタを通してクラスに注入するなどして、依存関係を再考します。一度それを行うと、単体テスト時に、静的データから読み込む独自のInputStreamを渡すことができ、生産コードではSystem.inを注入できます。

+1

+1これを理解すると、実際にはオブジェクトデザインが異なって見えます。 –

+0

グローバル[周囲]状態を読み取ることは、常に悪い設計です。多くの影響の1つは、テストを貧弱にすることです。/"注入"は無意味な言葉です。それは、コンストラクタを使用するはずの方法でコンストラクタを使用するだけです。入力オブジェクトへのアクセスは*付与されます。 –

+0

@Tom:これは依存性注入の一種であるため、私は「注射する」と言った。依存関係をコンストラクタに渡すことを伴わない他の形式の依存関係注入があります。 –

2

System.inとSystem.outへの参照を変数に渡すか、テストでオーバーライドできるメソッドの値を(ByteArrayInput/OutputStreamのような他のストリームによって) System.setOutとSystem.setIn、デフォルトのストリームを置き換えてテストを実行し、出力を検証し、戻ってそれらを設定する。

+0

System.inに別の値を割り当てた後で、System.inをリセットするにはどうすればよいですか? – panny

+1

'PrintStream oldSystemIn = System.in; System.setIn( '...'); '...'; System.setIn(oldSystemIn); ' - preferrably try ... finallyブロックです。依存性注入の場合は+1 – mihi

2

ユーザー入力を模倣するMockオブジェクトを作成できます。