使用系统规则测试System.in和System.out

编写单元测试是软件开发的组成部分。 当您的被测类与操作系统交互时,您必须解决的一个问题是模拟其行为。 这可以通过使用模拟代替Java Runtime Environment(JRE)提供的实际对象来完成。 支持Java的模拟的库是例如嘲笑或jMock

当您完全控制对象的实例化时,模拟对象是一件好事。 在处理标准输入和标准输出时,这有点棘手,但并非不可能,因为java.lang.System允许您替换标准InputStreamOutputStream

System.setIn(in);
System.setOut(out);

为了不必在每个测试用例前后都手动替换流,可以使用org.junit.rules.ExternalResource 。 此类提供了两个方法before()after() ,就像它们的名称所暗示的那样,在每个测试用例之前和之后调用。 这样,您可以轻松地设置和清除一类中所有测试所需的资源。 或者,回到原始问题,替换java.lang.System的输入和输出流。

我上面所描述的完全由库system-rules实现 。 要查看其工作原理,让我们从一个简单的示例开始:

public class CliExample {
    private Scanner scanner = new Scanner(System.in, "UTF-8");
 
    public static void main(String[] args) {
        CliExample cliExample = new CliExample();
        cliExample.run();
    }
 
    private void run() {
        try {
            int a = readInNumber();
            int b = readInNumber();
            int sum = a + b;
            System.out.println(sum);
        } catch (InputMismatchException e) {
            System.err.println("The input is not a valid integer.");
        } catch (IOException e) {
            System.err.println("An input/output error occurred: " + e.getMessage());
        }
    }
 
    private int readInNumber() throws IOException {
        System.out.println("Please enter a number:");
        String nextInput = scanner.next();
        try {
            return Integer.valueOf(nextInput);
        } catch(Exception e) {
            throw new InputMismatchException();
        }
    }
}

上面的代码从标准输入中读取两个整数,并打印出其总和。 如果用户提供了无效的输入,则程序应在错误流上输出适当的消息。

在第一个测试用例中,我们要验证程序是否正确地将两个数字求和并打印出结果:

public class CliExampleTest {
    @Rule
    public final StandardErrorStreamLog stdErrLog = new StandardErrorStreamLog();
    @Rule
    public final StandardOutputStreamLog stdOutLog = new StandardOutputStreamLog();
    @Rule
    public final TextFromStandardInputStream systemInMock = emptyStandardInputStream();
 
    @Test
    public void testSuccessfulExecution() {
        systemInMock.provideText("2\n3\n");
        CliExample.main(new String[]{});
        assertThat(stdOutLog.getLog(), is("Please enter a number:\r\nPlease enter a number:\r\n5\r\n"));
    }
    ...
}

为了模拟System.in我们利用系统规则的TextFromStandardInputStream 。 通过调用emptyStandardInputStream()用一个空的输入流初始化实例变量。 在测试用例本身中,我们通过在适当的位置调用带有换行符的provideText()来为应用程序提供信息。 然后,我们调用应用程序的main()方法。 最后,我们必须断言该应用程序已将两个输入语句和结果写入标准输入。 后者是通过StandardOutputStreamLog实例完成的。 通过调用其方法getLog()我们可以检索在当前测试用例中已写入标准输出的所有内容。

StandardErrorStreamLog可以类似地用于验证写入标准错误的内容:

@Test
public void testInvalidInput() throws IOException {
    systemInMock.provideText("a\n");
    CliExample.main(new String[]{});
    assertThat(stdErrLog.getLog(), is("The input is not a valid integer.\r\n"));
}

除此之外, system-rules还提供了使用System.getProperty()System.setProperty()System.exit()System.getSecurityManager()

结论 :通过系统规则测试,带有单元测试的命令行应用程序比使用junit的规则本身更加简单。 每个测试用例前后的所有样板代码都在一些易于使用的规则之内,用于更新系统环境。

PS:您可以在此处找到完整的资源。

翻译自: https://www.javacodegeeks.com/2015/01/testing-system-in-and-system-out-with-system-rules.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值