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

10

我一直在开发一个命令行工具,它在特定输入时调用 System.exit()不想使用异常)

我熟悉 Java:如何测试调用 System.exit() 的方法?及其最优雅的 方法

不幸的是,这并不够纯粹,因为我不得不添加依赖项到 system-rulesjunit-interface

是否有任何常见模式来处理 specs2 中的 System.exit,比我当前不使用 specs2 的方法更加纯粹?

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"});
    }
}

1
请查看https://groups.google.com/forum/#!topic/scalatest-users/pyKHtcP6HXM,其中ScalaTest的作者Bill Venners提供了有用的答案。 - Kevin Meredith
2个回答

12
如果您真的希望使用 System.exit() 方法,最简单的测试方法是将您的 SecurityManager 替换为一个会在调用 System.exit() 时抛出 ExitException(继承自 SecurityException)的对象:

SystemExitSpec

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
    }
}

抱歉混乱了,你应该还原你最后的更改。我们必须使用你的建议,为什么?因为 specs2 不验证状态代码,由于一个实现 - sergiusz.kierat
你可以检查异常信息,对吧? - Ven
或者简单地使用 must throwAn [ExitException] - Ven
我可以使用must throwA [ExitException],但它与以下try-catch代码块不等效:try { myObject.myFunctionExiting() Failure("shouldn't read this code") } catch { case e: ExitException => e.status must_== 1 } - sergiusz.kierat
让我们在聊天中继续这个讨论 - sergiusz.kierat
显示剩余3条评论

1

第一种选择:使用异常代替System.exit

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

第三种选择:模拟System.exit。有许多可能性可以做到这一点,提到的一种方式相当不错。

然而,在specs2中没有特定的模式来处理System.exit。个人建议使用第一或第二个选项。


  1. 对我来说第一个选项不可接受。
  2. 第二个选项对我来说有点过度设计,比 system-rules 更复杂。
  3. 第三个选项与之前的相同。
在我看来,使用 system-rules 是简洁的,只是它不使用 specs2 :(
- sergiusz.kierat
2
对于第三个选项,您可以使用模拟库来模拟静态类,例如PowerMock。 - dveim
1
另一个选项是提供/注入一个简单的组件,该组件本身调用System.exit(),并通过标准模拟框架断言该组件被正确调用。 - Brian Agnew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接