# Unit Test consolen ein-/ausgaben.



## kama (15. Feb 2011)

Hallo,

hänge gerade an einem Problem fest...habe folgende Klasse....zu der ich einen Unit Test schreibe...


```
public class Interactive {
    private static Logger LOGGER = Logger.getLogger(Interactive.class);

    public static String readString(String prompt) {
        System.out.println(prompt + ": ");
        return readLine();
    }

    public static boolean readYesNo(String prompt) {
        String result = readString(prompt);
        if (result.trim().toLowerCase().startsWith("y")) {
            return true;
        } else {
            return false;
        }
    }

    public static String readPassword(String prompt) {
        String result = null;
        Console cons = System.console();
        char[] passwd;
        if (cons == null) {
            LOGGER.error("Console is null!");
        } else {
            passwd = cons.readPassword("%s: ", prompt);
            // HINT: Security flaw...Not filling up the password it would in
            // memory over the runtime.
            // java.util.Arrays.fill(passwd, ' ');
            result = passwd.toString();
        }
        return result;
    }

    public static String readLine() {
        String strInput = null;
        try {
            BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
            strInput = input.readLine();
            input.close();
        } catch (Exception e) {
            LOGGER.error("Failure during console input:", e);
        }
        return strInput;
    }
}
```
und der Unit Test (TestNG) sieht derzeit so aus:

```
@BeforeMethod
    public void beforeMethod() {
        LOGGER.info("beforeMethod()");
        out = new ByteArrayOutputStream();
        PrintStream ps = new PrintStream(out);
        StringWriter sw = new StringWriter();
        System.setOut(ps);
        System.setIn(in);
    }

    @AfterMethod
    public void afterMethod() {
        System.setOut(System.out);
        System.setIn(System.in);
    }

    @Test
    public void testApp() {
        Interactive ia = new Interactive();
        String result = ia.readString("This is a Test");
        Assert.assertEquals("Test Input", result);
    }
```
so nun zu meinem Problem:

In der Method testApp (Unit Test) möchte ich einen String einlesen mit einem Problem. Das Problem dabei ist, dass mithilfe des Unit Tests prüfen möchte, ob meine Routine (readString) so läuft wie sie soll....
Dazu muss ich Daten auf den stdin schreiben (nämlich das was der Benutzer üblicherweise eintippen würde) und auf dem stdout das Ergebnis lesen...

Um nun den stdin umzuleiten (redirect) habe ich per System.setIn(...) einen Stream angegeben...Das Problem dabei ist aber, dass das ein InputStream ist und ich somit auf dem nicht schreiben kann....eventuell habe ich gerade nur ein Dickes Brett vor dem Kopf....

Hat da einer eine Idee oder Vorschlag ? 

Gruß
Karl Heinz Marbaise


----------



## tfa (15. Feb 2011)

Du könntest PipedInputStream verwenden oder den Stream selber mocken.


----------



## kama (15. Feb 2011)

Hallo,


erst einmal vielen Dank für den Tipp....
habe jetzt meinen Unit Test so geändert:

```
private OutputStream out = null;
    private PipedInputStream pin = null;
    private PipedOutputStream pout = null;

    @BeforeMethod
    public void beforeMethod() throws IOException {
        LOGGER.info("beforeMethod()");
        out = new ByteArrayOutputStream();

        pin = new PipedInputStream();
        pout = new PipedOutputStream();
        PrintStream ps = new PrintStream(out);

        System.setOut(ps);
        pout.connect(pin);
        System.setIn(pin);
    }
```
und meine Unit Tests sehen jetzt so aus:


```
@Test
    public void readStringTest() throws IOException {
        pout.write("Answer\n".getBytes());
        String result = Interactive.readString("This is a Test");
        Assert.assertEquals("Answer", result);
    }
```
So funktioniert es jetzt....

Vielen Dank für den Hinweise..

Gruß
Karl Heinz Marbaise


----------



## kama (15. Feb 2011)

Hi,

so einzig der folgende Code Abschnitt produziert noch probleme....

```
public static String readPassword(String prompt) {
        String result = null;
        Console cons = System.console();
        char[] passwd;
        if (cons == null) {
            LOGGER.error("Console is null!");
        } else {
            passwd = cons.readPassword("%s: ", prompt);
            // HINT: Security flaw...Not filling up the password it would in
            // memory over the runtime.
            // java.util.Arrays.fill(passwd, ' ');
            result = passwd.toString();
        }
        return result;
    }
```
So weit ich es verstehe und gelesen habe liefert mir System.console() nur auf der Command line auch ein Object zurück nicht aber während des Unit Tests....habe gerade mal gestöbert und bin erstaunt....

Gibt es keine einfache Möglichkeit eine Eingabe OHNE das Echo des eingegebenen Zeichens....
Ich habe hier etwas gefunden: Password Masking in the Java Programming Language aber das kommt mir doch sehr kompliziert vor um nur einfach eins Password einzulesen...

Gruß
Karl Heinz Marbaise


----------



## bygones (15. Feb 2011)

die Frage für mich ist - warum willst du die Methode in ihrer Form testen ? Es wäre ein Test der Console und nicht deiner Methode.

Ansonsten ist es ein schönes bsp wie global states / statics testen erschweren bis hin zum verhindern....


----------



## kama (15. Feb 2011)

Hi bygones,

das Problem habe ich ja beschrieben...Testen funktioniert nicht...
Ich selbst möchte den Code ja auch nicht so haben....habe ich mal eben so hin gesaut bis ich etwas besseres gefunden habe und eben beim Testen bin ich darauf gestoßen dass das nicht funktioniert mit dem Testen...also muss was anderes her...



kama hat gesagt.:


> Gibt es keine einfache Möglichkeit eine Eingabe OHNE das Echo des eingegebenen Zeichens....
> Ich habe hier etwas gefunden: Password Masking in the Java Programming Language aber das kommt mir doch sehr kompliziert vor um nur einfach eins Password einzulesen...


Aber da liegt mein Problem....

Gruß
Karl Heinz Marbaisea


----------



## bygones (15. Feb 2011)

scheint nicht direkt zu gehen...
ein paar tipps: How to mask a password in Java 5? - Stack Overflow



> With the JDK 6.0, you have the java sources of the classes, including Console : I just verified and this class has only Java 5.0 dependencies.
> 
> So, in your project, you can create a copy of this Console class, and then use the readPassword method. I did not try but it should work.


----------



## kama (15. Feb 2011)

Hi,



bygones hat gesagt.:


> scheint nicht direkt zu gehen...
> ein paar tipps: How to mask a password in Java 5? - Stack Overflow


Ja hatte ich auch schon gefunden und einige mehr...

Aber trotzdem vielen Dank.

Gruß
Karl Heinz Marbaise


----------

