โซลูชั่นส่วนใหญ่จะ
- ยุติการทดสอบ (วิธีการไม่ใช่การวิ่งทั้งหมด) ช่วงเวลาที่
System.exit()
เรียกว่า
- ละเว้นการติดตั้งแล้ว
SecurityManager
- บางครั้งค่อนข้างเฉพาะเจาะจงกับกรอบการทดสอบ
- จำกัด ให้ใช้ได้สูงสุดหนึ่งครั้งต่อหนึ่งกรณีทดสอบ
ดังนั้นการแก้ปัญหาส่วนใหญ่ไม่เหมาะสำหรับสถานการณ์ที่:
- การตรวจสอบผลข้างเคียงจะต้องดำเนินการหลังจากการโทรไปที่
System.exit()
- ผู้จัดการความปลอดภัยที่มีอยู่เป็นส่วนหนึ่งของการทดสอบ
- ใช้กรอบการทดสอบที่แตกต่างกัน
- คุณต้องการให้มีการยืนยันหลายรายการในกรณีทดสอบเดียว สิ่งนี้อาจไม่แนะนำอย่างเคร่งครัด แต่สามารถทำได้อย่างสะดวกสบายในบางครั้งโดยเฉพาะอย่างยิ่งเมื่อใช้ร่วมกับ
assertAll()
ตัวอย่างเช่น
ฉันไม่พอใจกับข้อ จำกัด ที่กำหนดโดยโซลูชันที่มีอยู่ซึ่งนำเสนอในคำตอบอื่น ๆ และทำให้เกิดอะไรขึ้นกับตัวฉันเอง
คลาสต่อไปนี้ให้วิธีการassertExits(int expectedStatus, Executable executable)
ที่ยืนยันว่าSystem.exit()
ถูกเรียกด้วยstatus
ค่าที่ระบุและการทดสอบสามารถดำเนินต่อไปหลังจากนั้น มันทำงานแบบเดียวกับ JUnit assertThrows
5 นอกจากนี้ยังเคารพผู้จัดการความปลอดภัยที่มีอยู่
มีปัญหาหนึ่งที่เหลืออยู่: เมื่อโค้ดภายใต้การทดสอบติดตั้งตัวจัดการความปลอดภัยใหม่ซึ่งแทนที่ตัวจัดการความปลอดภัยที่กำหนดโดยการทดสอบอย่างสมบูรณ์ 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()
พร้อมข้อความที่ปรับแต่ง