Scala:如何测试调用System.exit()的方法?

Scala:如何测试调用System.exit()的方法?,scala,unit-testing,sbt,specs2,testability,Scala,Unit Testing,Sbt,Specs2,Testability,我一直在开发一个命令行工具,它可以在某些输入上调用System.exit()(不想使用异常代替) 我很熟悉,它是最优雅的 不幸的是,它不够纯净,因为我不得不将依赖项添加到 是否有处理系统的通用模式。在规范2中退出,这比我目前不使用规范2中的方法更纯粹 import org.junit.Rule; import org.junit.Test; import org.junit.contrib.java.lang.system.ExpectedSystemExit; public class Co

我一直在开发一个命令行工具,它可以在某些输入上调用
System.exit()
(不想使用异常代替)

我很熟悉,它是最优雅的

不幸的是,它不够纯净,因为我不得不将依赖项添加到

是否有处理
系统的通用模式。在规范2中退出
,这比我目前不使用规范2中的方法更纯粹

import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.ExpectedSystemExit;

public class ConverterTest {
    @Rule
    public final ExpectedSystemExit exit = ExpectedSystemExit.none();

    @Test
    public void emptyArgs() {
        exit.expectSystemExit();
        Converter.main(new String[]{});
    }

    @Test
    public void missingOutArgument() {
        exit.expectSystemExitWithStatus(1);
        Converter.main(new String[]{"--in", "src/test/resources/078.xml.gz"});
    }
}

第一个选项:使用一些异常而不是
系统。退出

第二个选项:在单独的线程中调用应用程序并检查返回代码

第三个选项:模拟
系统。退出
。有很多种可能性可以做到这一点,提到的一个是相当好的


但是,没有可用于
系统的
规范2
特定模式。退出
。就个人而言,我建议您选择第一个或第二个选项。

如果您真的希望使用
System.exit()
的方法,最简单的测试方法是将
SecurityManager
替换为在
System.exit()时抛出
ExitException
(子类化
SecurityException
)的方法
称为:

classSystemExitSpec

import java.security.Permission

import org.specs2.mutable.Specification
import org.specs2.specification.BeforeAfterAll

sealed case class ExitException(status: Int) extends SecurityException("System.exit() is not allowed") {
}

sealed class NoExitSecurityManager extends SecurityManager {
  override def checkPermission(perm: Permission): Unit = {}

  override def checkPermission(perm: Permission, context: Object): Unit = {}

  override def checkExit(status: Int): Unit = {
    super.checkExit(status)
    throw ExitException(status)
  }
}


abstract class SystemExitSpec extends Specification with BeforeAfterAll {

  sequential

  override def beforeAll(): Unit = System.setSecurityManager(new NoExitSecurityManager())

  override def afterAll(): Unit = System.setSecurityManager(null)
}
import org.specs2.execute.Failure

import scala.io.Source

class ConverterSpec extends SystemExitSpec {

"ConverterSpec" should {

    "empty args" >> {
      try {
        Converter.main(Array[String]())
        Failure("shouldn't read this code")
      } catch {
        case e: ExitException =>
          e.status must_== 1
      }
      1 must_== 1
    }
}
测试转换器规格

import java.security.Permission

import org.specs2.mutable.Specification
import org.specs2.specification.BeforeAfterAll

sealed case class ExitException(status: Int) extends SecurityException("System.exit() is not allowed") {
}

sealed class NoExitSecurityManager extends SecurityManager {
  override def checkPermission(perm: Permission): Unit = {}

  override def checkPermission(perm: Permission, context: Object): Unit = {}

  override def checkExit(status: Int): Unit = {
    super.checkExit(status)
    throw ExitException(status)
  }
}


abstract class SystemExitSpec extends Specification with BeforeAfterAll {

  sequential

  override def beforeAll(): Unit = System.setSecurityManager(new NoExitSecurityManager())

  override def afterAll(): Unit = System.setSecurityManager(null)
}
import org.specs2.execute.Failure

import scala.io.Source

class ConverterSpec extends SystemExitSpec {

"ConverterSpec" should {

    "empty args" >> {
      try {
        Converter.main(Array[String]())
        Failure("shouldn't read this code")
      } catch {
        case e: ExitException =>
          e.status must_== 1
      }
      1 must_== 1
    }
}

1.第一种选择对我来说是不可接受的。2.第二个选项对我来说有点过于复杂,比系统规则3更复杂。第三个选项-与之前的IMO相同,使用系统规则是简洁的,只是它不使用specs2:(对于第三个选项,您可以使用模拟静态类的模拟库,例如PowerMock。另一个选项是提供/注入一个本身调用system.exit()的简单组件),并通过标准模拟框架断言该组件被正确调用。我可能错过了这一部分。不过,最好有
myObject。myfunctionexit()必须是throwAn(ExitException(1))
很抱歉弄糟了,您应该恢复上次更改,我们必须使用您的建议,为什么?因为specs2没有验证状态。code,由于存在异常,您可以检查异常消息,对吗?或者简单地使用
必须通过[ExitException]
我可以使用
必须通过[ExitException]
,但这与try不同{myObject.myFunctionExitting()失败(“不应该读取此代码”)}catch{case e:ExitException=>e.status must==1}签出,其中Bill Venners(ScalaTest的作者)提供了一个有用的答案。