首页 > 解决方案 > 重定向 System.in ByteArrayInputStream 读取一个 JUnit 测试太晚了

问题描述

我目前正在编写用于自动测试学生任务的 Junit 测试。主题是java中的控制台输入。我有多个测试需要模拟用户输入并检查测试方法的正确行为(方法工作正常)。

我目前的问题: ByteArrayInputStream 设置为System.in不会在需要时发布,但稍后会进行一次测试(见下图)。

我尝试重置流,使其成为静态,使其成为非静态,System.in前后设置标准,尝试读取方法,切换 java 版本(从 SE13 到 1.8)。不同时间的所有尝试,ofc。

在此处输入图像描述

图中输出说明:

它来自我们的自动化 JUnit 框架。这两个测试依赖于接受用户输入的测试方法。这 ”?” 在一行的开头表示测试的方法处于活动状态并正在等待。STARTING TEST 行之后的前两个单词应该被注入。

JUnit测试代码:

final  static InputStream STDIN = System.in;
static ByteArrayInputStream bais;
final static String[] INJECTIONS = { "abc", "def", "ghi", "jkl", "mmmm", "klopp", "urgl", "gurle", "ding", "dong" };

private static void inject(String injection, Object o, MethodSignature ms) {
    System.out.println(injection);

    try {
        ByteArrayInputStream bais = new ByteArrayInputStream(injection.getBytes("UTF-8"));

        System.setIn(bais);
        System.out.println("Injection Bytes: "+injection.getBytes().length);
        System.out.println("Available for injection: " + System.in.available());

        ms.getMethod().invoke(o);

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        System.setIn(STDIN);
    }
}

private static String getStringInject(String injection, Object o, MethodSignature ms) {
    String out = null;
    System.out.println(injection);
    try {

        ByteArrayInputStream bais = new ByteArrayInputStream(injection.getBytes("UTF-8"));

        System.setIn(bais);
        System.out.println("Injection Bytes: "+injection.getBytes().length);
        System.out.println("Available for injection: " + System.in.available());
        System.in.reset();
        out = (String) ms.getMethod().invoke(o);

    } catch (Exception e) {
        e.printStackTrace();
    }
    finally {
        System.setIn(STDIN);
    }
    return out;
}

@Test
public void checkReadFromConsoleCorrectReturnTest() {

    Object o = createObject(csMain.getC());
    if (o == null) {
        addFail(csMain.getObjectFail());
        return;
    }
    String injection = INJECTIONS[ThreadLocalRandom.current().nextInt(0, INJECTIONS.length)];

    String output = getStringInject(injection + System.lineSeparator() + "END" + System.lineSeparator(), o,
            msReadFromConsole);

    if (output == null || output.isEmpty()) {
        addFail(msReadFromConsole.getMethodNoReturnString());
        return;
    }

}

@Test
public void checkReadCorrectEndingTriggerTest() {

    Object o = createObject(csMain.getC());
    if (o == null) {
        addFail(csMain.getObjectFail());
        return;
    }
    String injection = INJECTIONS[ThreadLocalRandom.current().nextInt(0, INJECTIONS.length)]
            + System.lineSeparator() + "END" + System.lineSeparator();


    inject(injection, o, msRead);
}

测试的java方法:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class ConsoleReader implements IConsoleReader {

    ArrayList<String> reads;
    BufferedReader br;

    public ConsoleReader() {
        reads = new ArrayList<String>();
        br = new BufferedReader(new InputStreamReader(System.in));
    }

    public void read() {
        String input = readFromConsole();
        while (true) {
            if (input == null || input.isEmpty()) {
                System.out.println("ERROR: null");
                return;
            }
            input = input.trim().toUpperCase();

            if (input.equals("END")) {
                System.out.println("Done.");
                return;
            }

            reads.add(input);
            input = readFromConsole();
        }
    }

    public String readFromConsole() {
        System.out.print("? ");
        String out = null;
        try {
            out = br.readLine();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        System.out.println(out);
        return out;
    }
}

非常感谢您的帮助。无法更改使用的 Junit 库或添加其他外部库 atm。

标签: javainputbufferjunit4system.in

解决方案


我编写了以下代码段供您运行:

@Test
public void test_byteArrayInputStream() {
    InputStream STDIN = System.in;
    String message = "test" + System.lineSeparator();
    try (ByteArrayInputStream in = new ByteArrayInputStream(message.getBytes("UTF-8"))) {
        System.setIn(in);

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        assertEquals("test", br.readLine()); // this succeeds
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        System.setIn(STDIN);
    }
}

如您所见,从流中BufferedReader正确准备好"test"。我在代码块之后使用了AutoClosable方面ByteArrayInputStream来关闭它。

由于这不能解决您的问题,因此我不确定问题是否源于周围的框架。更具体地说,对于从测试用例 1 到测试用例 2 的值的跨越,我能想到的唯一解释是,该对象没有被重新实例化,而是以某种方式重用。由于缺少此代码,因此无法确定。


推荐阅读