Çoğu çözüm
- Anı
System.exit()
çağrıldığında testi (yöntem, tüm çalışma değil) sonlandırın
- önceden kurulmuş olanları yoksay
SecurityManager
- Bazen bir test çerçevesine oldukça spesifik olun
- test senaryosu başına maksimum bir kez kullanılmasını kısıtla
Bu nedenle, çoğu çözüm aşağıdaki durumlarda uygun değildir:
- Yan etkilerin doğrulanması, şu çağrıdan sonra yapılacaktır:
System.exit()
- Mevcut bir güvenlik yöneticisi testin bir parçasıdır.
- Farklı bir test çerçevesi kullanılır.
- Tek bir test durumunda birden çok doğrulama yapmak istiyorsunuz. Bu kesinlikle tavsiye edilmeyebilir, ancak özellikle
assertAll()
örneğin ile birlikte zaman zaman çok uygun olabilir .
Diğer cevaplarda sunulan mevcut çözümlerin getirdiği kısıtlamalardan memnun değildim ve bu yüzden kendi başıma bir şey buldum.
Aşağıdaki sınıf bir yöntem temin assertExits(int expectedStatus, Executable executable)
belirtmektedir System.exit()
belirli bir çağrılır status
değeri ve test bunu sonra da devam edebilir. JUnit 5 ile aynı şekilde çalışır assertThrows
. Ayrıca mevcut bir güvenlik yöneticisine de saygı gösterir.
Kalan bir sorun var: Test edilen kod, test tarafından ayarlanan güvenlik yöneticisinin yerini alan yeni bir güvenlik yöneticisi yüklediğinde. SecurityManager
Benim bildiğim diğer tüm tabanlı çözümler aynı problemle karşı karşıya.
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;
}
}
}
Sınıfı şu şekilde kullanabilirsiniz:
@Test
void example() {
assertExits(0, () -> System.exit(0)); // succeeds
assertExits(1, () -> System.exit(1)); // succeeds
assertExits(2, () -> System.exit(1)); // fails
}
Kod, gerekirse JUnit 4, TestNG veya başka bir çerçeveye kolayca taşınabilir. Çerçeveye özgü tek öğe testin başarısız olmasıdır. Bu kolayca çerçeve bağımsız bir şeye değiştirilebilir ( 4 Haziran dışında) Rule
assertExits()
Özelleştirilebilir mesajlarla aşırı yükleme gibi iyileştirme için yer vardır .