대부분의 솔루션은
- 모멘트
System.exit()
가 호출 되는 테스트 종료 (전체 실행이 아닌 메소드)
- 이미 설치된 무시
SecurityManager
- 때때로 테스트 프레임 워크에 매우 구체적
- 테스트 사례 당 최대 한 번만 사용하도록 제한
따라서 대부분의 솔루션은 다음과 같은 상황에 적합하지 않습니다.
- 부작용 확인은 전화를 한 후 수행해야합니다.
System.exit()
- 기존 보안 관리자가 테스트의 일부입니다.
- 다른 테스트 프레임 워크가 사용됩니다.
- 단일 테스트 사례에서 여러 번의 검증을 원합니다. 이것은 엄격하게 권장되지는 않지만 특히 예를 들어와 함께 사용
assertAll()
하면 매우 편리 할 수 있습니다 .
나는 다른 답변에 제시 된 기존 솔루션에 의해 부과 된 제한에 만족하지 않아서 스스로 무언가를 생각해 냈습니다.
다음 클래스는 지정된 값으로 호출 assertExits(int expectedStatus, Executable executable)
되는 어설 션을 제공하며 테스트 후에도 계속할 수 있습니다. JUnit 5와 같은 방식으로 작동합니다 . 또한 기존 보안 관리자를 존중합니다.System.exit()
status
assertThrows
테스트중인 코드가 테스트에 의해 설정된 보안 관리자를 완전히 대체하는 새 보안 관리자를 설치하는 경우 하나의 문제가 남아 있습니다. SecurityManager
나에게 알려진 다른 모든 솔루션은 같은 문제를 겪습니다.
import java.security.Permission;
import static java.lang.System.getSecurityManager;
import static java.lang.System.setSecurityManager;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
public enum ExitAssertions {
;
public static <E extends Throwable> void assertExits(final int expectedStatus, final ThrowingExecutable<E> executable) throws E {
final SecurityManager originalSecurityManager = getSecurityManager();
setSecurityManager(new SecurityManager() {
@Override
public void checkPermission(final Permission perm) {
if (originalSecurityManager != null)
originalSecurityManager.checkPermission(perm);
}
@Override
public void checkPermission(final Permission perm, final Object context) {
if (originalSecurityManager != null)
originalSecurityManager.checkPermission(perm, context);
}
@Override
public void checkExit(final int status) {
super.checkExit(status);
throw new ExitException(status);
}
});
try {
executable.run();
fail("Expected System.exit(" + expectedStatus + ") to be called, but it wasn't called.");
} catch (final ExitException e) {
assertEquals(expectedStatus, e.status, "Wrong System.exit() status.");
} finally {
setSecurityManager(originalSecurityManager);
}
}
public interface ThrowingExecutable<E extends Throwable> {
void run() throws E;
}
private static class ExitException extends SecurityException {
final int status;
private ExitException(final int status) {
this.status = status;
}
}
}
다음과 같이 클래스를 사용할 수 있습니다.
@Test
void example() {
assertExits(0, () -> System.exit(0)); // succeeds
assertExits(1, () -> System.exit(1)); // succeeds
assertExits(2, () -> System.exit(1)); // fails
}
필요한 경우 코드를 JUnit 4, TestNG 또는 기타 프레임 워크로 쉽게 포팅 할 수 있습니다. 프레임 워크 고유의 유일한 요소는 테스트에 실패한 것입니다. 이것은 Junit 4 이외의 프레임 워크 독립적 인 것으로 쉽게 변경 될 수 있습니다. Rule
예를 들어, assertExits()
사용자 정의 가능한 메시지로 오버로드 하는 개선의 여지가 있습니다 .