Java Top.

开始使用Spring 5和Spring Boot 2,通过学习春天课程:

>>查看课程

1.概述

有时在编写单元测试时,我们可能需要测试直接交互的代码系统类。通常在命令行工具等应用程序中调用system . exit直接或读取参数system.in.

在本教程中,我们将看一看名为系统规则它提供了一组JUNIT规则用于测试使用该代码系统班级

2.Maven的依赖关系

首先,让我们添加系统规则的依赖对我们的pom.xml:

<依赖项>  com.github.stefanbirkner  系统 - 规则  1.19.0  

我们也会增加系统lambda.可用的依赖项Maven Central.:

<依赖项>  com.github.stefanbirkner   SYSTEM-LAMBDA  <版本> 1.1.0  

由于系统规则没有直接支持JUnit5,我们添加了最后一个依赖项。这提供了在测试中使用的System Lambda包装器方法。有一个扩展基于这种方法的替代方法系统存根

3.使用系统属性

为了快速回顾,Java平台使用一个属性对象提供有关本地系统和配置的信息。金宝搏官网188be我们可以轻松地打印出属性:

System.getProperties() . foreach ((key, value) ->Println(键+“:”+值));

正如我们所看到的,属性包括当前用户(Java Runtime的当前版本)等信息,以及文件路径名分隔符:

java.version:1.8.0_221 file.separator:/ user.home:/用户/ baeld金宝搏188体育ung os.name:macos x ...

我们还可以通过使用来设置自己的系统属性System.setProperty方法。应在使用我们的测试中使用系统属性时注意,因为这些属性是JVM-Global。

例如,如果我们设置了系统属性,我们应该确保在测试完成或发生故障时,我们应该确保将属性恢复到原始值。这有时会导致麻烦的设置和拆除代码。但是,如果我们忽略这一点,它可能导致我们的测试中的意外副作用。

在下一节中,我们将看到我们如何提供,清洁,并确保在我们的测试中以简洁而简单的方式完成后恢复系统属性值。

4.提供系统属性

让我们想象我们有一个系统属性log_dir.它包含了我们的日志应该被写入的位置,我们的应用程序在启动时设置了这个位置:

system.setProperty(“log_dir”,“/ tmp 金宝搏188体育/ baeldung / logs”);

4.1。提供单一财产

现在让我们考虑从我们的单元测试中,我们想要提供不同的价值。我们可以使用这件事ProvideSystemProperty规则:

公共类ProvidessystemPropertyWithRuleUnittest {@rule公共最终Final SubptyStemProperty ProvideSystemPropertyrule = New ServiceStemProperty(“log_dir”,“测试/资源”);@test公共void给gentrovidesystemproperty_whengetlogdir_thenlogdirisprovidedsuccessulus(){assertequals(应该提供“测试/资源”,system.getproperty(“log_dir”));} //单元测试定义继续}

使用ProvideSystemProperty规则,我们可以为定向系统属性设置任意值,以便从我们的测试中使用。在这个例子中,我们设置了log_dir.财产给我们测试/资源目录,以及从我们的单元测试中,只是断言测试属性值已成功提供。

的值打印出来log_dir.当我们的测试类完成时:

@AfterClass public static void tearDownAfterClass()抛出异常{System.out.println(System.getProperty(“log_dir”));}

我们可以看到财产的价值已经恢复到原来的价值:

/ tmp金宝搏188体育 / baeldung /日志

4.2。提供多个属性

如果我们需要提供多个属性,我们可以使用在我们的测试中需要链接到许多属性值的方法:

@Rule public final ProvideSystemProperty providesSystemPropertyRule = new ProvideSystemProperty(“log_dir”,“test/resources”)。(“another_property”、“another_value”)

4.3。提供文件的属性

同样,我们还可以使用使用文件或类路径资源提供属性ProvideSystemProperty规则:

@rule public final supplystemproperty otherystempropertyfromfilerule = foverystemproperty.fromresource(“/ test.properties”);@Test公共void给予物业vovidesystempropertyfromfile_whengetname_thennamisprovidedsuccesspulle(){assertequals(“名称应该提供”,“baeldung”,system.getproperty(“金宝搏188体育名称”));assertequals(“版本应该提供”,“1.0”,system.getProperty(“版本”));}

在上面的例子中,我们假设我们有一个test.properties.类路径上的文件:

name 金宝搏188体育= = 1.0 baeldung版本

4.4。使用JUnit5和Lambdas提供属性

如前所述,我们还可以使用库的系统Lambda版本来实现与JUnit5兼容的测试。

让我们看看如何使用此版本的库来实现我们的测试:

@BeforeAll static void setUpBeforeClass()抛出异常{系统。setProperty(“log_dir”、“/ tmp 金宝搏188体育/ baeldung /日志”);} @Test void givenSetSystemProperty_whenGetLogDir_thenLogDirIsProvidedSuccessfully() throws Exception {restoreSystemProperties(() -> {System. setsystemproperty_whengetlogdir_thenlogdirisprovidedsuccessfully () throws Exception}setProperty(“log_dir”、“测试/资源”);assertEquals("log_dir应该被提供","test/resources", System.getProperty("log_dir"));});assertEquals("log_dir应该被提供","/tmp/baeldung/logs",金宝搏188体育 System.getProperty("log_dir"));}

在这个版本中,我们可以使用restoreystemproperties.方法执行给定语句。在此语句中,我们可以设置并提供我们的系统属性所需的值。正如我们在此方法完成执行后,值log_dir.和以前一样吗/ tmp金宝搏188体育 / baeldung /日志

不幸的是,对于使用restoreystemproperties.方法。

5.清算系统属性

有时,我们可能希望在测试开始时清除一组系统属性,并在测试结束时恢复它们的原始值,而不管它是通过还是失败。

我们可以使用clearsystemproperties.为此目的规则:

@rule public final clearsystemproperties usernameisclearedrule = new clearsystemproperties(“user.name”);@test public void gentclearusernameproperty_whengetusername_thenull(){assertnull(system.getproperty(“user.name”));}

系统属性用户名是预定义的系统属性之一,其中包含用户帐户名。正如在上面的单元测试中所期望的,我们清除这个属性,并从我们的测试中检查它是否为空。

方便地,我们也可以将多个属性名称传递给clearsystemproperties.构造函数。

6.嘲笑system.in.

有时,我们可能会创建交互式命令行应用程序来进行读取system.in.

在本节中,我们将使用一个非常简单的示例,从标准输入中读取名字和姓氏,并将它们连接在一起:

private String getFullname() {try (Scanner Scanner = new Scanner(System.in)) {String firstName = Scanner .next();字符串姓氏= scanner.next();返回字符串。join(“”,名,姓);}}

系统规则包含textfromstandardinputstream.我们可以用来指定调用时应该提供的行system.in.:

@rule公共最终TextFromStandAddInputStream SystemInmock = limentAddInputStream();@test public viventwonames_whensysteminmock_thennamesjoinedtogether(){systeminmock.providelines(“jonathan”,“cook”);assertequals(“名字应该连接”,“jonathan cook”,getfullname());}

我们通过使用它来完成此操作providesLines方法,其参数为可变参数参数来启用指定多个值。

在这个例子中,我们在调用getFullname方法,在哪里system.in.引用。每次调用时,将返回提供的两个行值scanner.next ()

让我们来看看我们如何在使用System Lambda的测试中达到同样的测试:

@test viventwonames_whensysteminmock_thennamesjoinedTogether()抛出异常{withtextfromsystemin(“jonathan”,“cook”)。Execute(() - > {assertequals(“名字应该连接”,“jonathan cook”,getfullname());});}

在这种变体中,我们使用类似的命名withTextFromSystemIn方法,该方法让我们指定所提供的system.in.值。

在两种情况下,重要的是在测试完成后,原始值system.in.将恢复。

7.测试system . outSystem.err

在之前的教程中,我们看到了如何使用系统规则进行单元测试system.out.println()

方便地,我们可以应用几乎相同的方法来测试与标准错误流交互的测试代码。这次我们使用systemerrrule:

@rule公共最终systemerrrule systemerrrule = new systemerrrule()。EnableLog();@test public void givensystemerrrule_wheninvokeprintln_thenlogsuccess(){printerror(“错误发生了Baeldung读者!”);金宝搏188体育assert.asserequals(“发生错误Baeldung读者!!”,s金宝搏188体育ystemerrrule.getlog()。修剪());私有void printerror(String输出){system.err.println(输出);}

好了!使用systemerrrule,我们可以拦截写入System.err。首先,我们开始记录写入的一切System.err通过致电enableLog我们的规则上的方法。然后我们只需调用GetLog.将文本写入系统。自从我们打电话之后enableLog

现在,让我们实现我们的测试的JUnit5版本:

@Test void giventapsystemerr_wheninvokeprintln_thenoutputisreturning dsuccessfully () throws Exception {String text = tapSystemErr(() -> {printError("一个错误发生Baeldung R金宝搏188体育eaders!!");});断言。assertEquals("发生错误Baeldung Reade金宝搏188体育rs!!", text.trim());}

在这个版本中,我们利用了tapSystemErr执行该语句并允许我们捕获传递给的内容的方法System.err

8.处理system . exit

命令行应用程序通常通过调用来终止system . exit如果我们想测试这样的应用程序,当遇到调用的代码时,我们的测试很可能会在它完成之前非正常终止system . exit

值得庆幸的是,系统规则提供了一个简洁的解决方案来处理此方法预期的系统精灵规则:

@rule公共最终预期的预期exitrule = permanialsystemexit.none();@test public void givensystemexitrule_whenappcallssystemexit_thenexitruleworkssssasexpected(){exitrule.expectsystemexitwithstatus(1);出口();私有void退出(){system.exit(1);}

使用预期的系统精灵规则允许我们从我们的测试中指定预期的system . exit ()调用。在这个简单的示例中,我们还使用Heeplystemexitwithstatus.方法。

在JUnit 5版本中,我们可以使用catchsystemexit.方法:

@test vivencatchsystemexit_whenappcallssystemexit_thenstatusisreturnedsuccessules()抛出异常{int statuscode = catchsystemexit(() - > {exit();});assertequals(“状态代码应为1:”,1,statuscode);}

9.结论

要汇总,请在本教程中,我们详细探讨了系统规则库。

首先,我们首先通过解释如何测试使用系统属性的代码。然后我们研究了如何测试标准输出和标准输入。最后,我们研究了如何处理调用的代码system . exit从我们的测试中。

系统规则库还提供支持从我们的测试提供环境变量和特殊安全管理。务必查看完整文档有关详细信息。

与往常一样,本文的完整源代码是可用的在github上

Java底部

开始使用Spring 5和Spring Boot 2,通过学习春天课程:

>>查看课程
评论在本文上关闭!