Scala: Как проверить методы, которые вызывают System.exit()?

Я разрабатывал инструмент командной строки, который вызывает System.exit() (не хочу использовать исключения вместо) на определенных входах.

Я знаком с Java: как тестировать методы, вызывающие System.exit()? и это самый элегантный подход.

К сожалению, это недостаточно чисто, из-за того, что мне пришлось добавить зависимости к системным правилам, junit-interface

Есть ли какая-то общая картина для борьбы с System.exit в specs2, который является более чистым, чем мой текущий подход, который не использует 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"});
    }
}

2 ответа

Решение

Если вы действительно хотите использовать метод, использующий System.exit(), самый простой способ проверить это было на самом деле называется заменить ваш SecurityManager с одним, который бросит ExitException (подклассы SecurityException) когда System.exit() называется:

Класс 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)
}

тест ConverterSpec

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

Первый вариант: использовать какое-то исключение вместо System.exit,

Второй вариант: вызвать приложение в отдельном потоке и проверить коды возврата.

Третий вариант: макет System.exit, Есть много возможностей сделать это, упомянутая очень хорошая.

Тем не менее, нет specs2-конкретный шаблон для работы с System.exit, Лично я бы предложил первый или второй варианты.

Другие вопросы по тегам