Java: Cara menguji metode yang memanggil System.exit ()?

198

Saya punya beberapa metode yang harus memanggil System.exit()input tertentu. Sayangnya, menguji kasus-kasus ini menyebabkan JUnit berakhir! Menempatkan panggilan metode di Thread baru tampaknya tidak membantu, karena System.exit()mengakhiri JVM, bukan hanya utas saat ini. Apakah ada pola umum untuk menangani ini? Sebagai contoh, dapatkah saya menggantikan rintisan System.exit()?

[EDIT] Kelas yang dimaksud sebenarnya adalah alat baris perintah yang saya coba uji di dalam JUnit. Mungkin JUnit bukan alat yang tepat untuk pekerjaan itu? Saran untuk alat pengujian regresi komplementer dipersilahkan (lebih disukai sesuatu yang terintegrasi dengan baik dengan JUnit dan EclEmma).

Chris Conway
sumber
2
Saya ingin tahu mengapa suatu fungsi akan memanggil System.exit () ...
Thomas Owens
2
Jika Anda memanggil fungsi yang keluar dari aplikasi. Misalnya, jika pengguna mencoba melakukan tugas, mereka tidak diizinkan melakukan lebih dari x kali berturut-turut, Anda memaksa mereka keluar dari aplikasi.
Elie
5
Saya masih berpikir bahwa dalam hal ini, harus ada cara yang lebih baik untuk kembali dari aplikasi daripada System.exit ().
Thomas Owens
27
Jika Anda menguji main (), masuk akal untuk memanggil System.exit (). Kami memiliki persyaratan bahwa pada kesalahan proses batch harus keluar dengan 1 dan pada keberhasilan keluar dengan 0.
Matthew Farwell
5
Saya tidak setuju dengan semua orang yang mengatakan System.exit()itu buruk - program Anda harus gagal dengan cepat. Melempar pengecualian hanya memperpanjang aplikasi dalam keadaan tidak valid dalam situasi di mana pengembang ingin keluar dan akan memberikan kesalahan palsu.
Sridhar Sarnobat

Jawaban:

216

Memang, Derkeiler.com menyarankan:

  • Mengapa System.exit()?

Alih-alih mengakhiri dengan System.exit (whateverValue), mengapa tidak membuang pengecualian yang tidak dicentang? Dalam penggunaan normal, itu akan melayang keluar sampai ke penangkap terakhir JVM dan menutup skrip Anda (kecuali Anda memutuskan untuk menangkapnya di suatu tempat di sepanjang jalan, yang mungkin berguna suatu hari nanti).

Dalam skenario JUnit itu akan ditangkap oleh kerangka kerja JUnit, yang akan melaporkan bahwa tes ini-dan-itu gagal dan bergerak dengan lancar ke yang berikutnya.

  • Cegah System.exit()untuk benar-benar keluar dari JVM:

Coba ubah TestCase untuk dijalankan dengan manajer keamanan yang mencegah pemanggilan System.exit, lalu tangkap SecurityException.

public class NoExitTestCase extends TestCase 
{

    protected static class ExitException extends SecurityException 
    {
        public final int status;
        public ExitException(int status) 
        {
            super("There is no escape!");
            this.status = status;
        }
    }

    private static class NoExitSecurityManager extends SecurityManager 
    {
        @Override
        public void checkPermission(Permission perm) 
        {
            // allow anything.
        }
        @Override
        public void checkPermission(Permission perm, Object context) 
        {
            // allow anything.
        }
        @Override
        public void checkExit(int status) 
        {
            super.checkExit(status);
            throw new ExitException(status);
        }
    }

    @Override
    protected void setUp() throws Exception 
    {
        super.setUp();
        System.setSecurityManager(new NoExitSecurityManager());
    }

    @Override
    protected void tearDown() throws Exception 
    {
        System.setSecurityManager(null); // or save and restore original
        super.tearDown();
    }

    public void testNoExit() throws Exception 
    {
        System.out.println("Printing works");
    }

    public void testExit() throws Exception 
    {
        try 
        {
            System.exit(42);
        } catch (ExitException e) 
        {
            assertEquals("Exit status", 42, e.status);
        }
    }
}

Pembaruan Desember 2012:

Akan mengusulkan dalam komentar menggunakan Aturan Sistem , kumpulan aturan JUnit (4.9+) untuk menguji kode yang digunakan java.lang.System.
Ini awalnya disebutkan oleh Stefan Birkner dalam jawabannya pada Desember 2011.

System.exit(…)

Gunakan ExpectedSystemExitaturan untuk memverifikasi yang System.exit(…)dipanggil.
Anda dapat memverifikasi status keluar juga.

Misalnya:

public void MyTest {
    @Rule
    public final ExpectedSystemExit exit = ExpectedSystemExit.none();

    @Test
    public void noSystemExit() {
        //passes
    }

    @Test
    public void systemExitWithArbitraryStatusCode() {
        exit.expectSystemExit();
        System.exit(0);
    }

    @Test
    public void systemExitWithSelectedStatusCode0() {
        exit.expectSystemExitWithStatus(0);
        System.exit(0);
    }
}
VONC
sumber
4
Tidak menyukai jawaban pertama, tetapi yang kedua cukup keren - saya tidak mengacaukan manajer keamanan dan menganggap mereka lebih rumit dari itu. Namun, bagaimana Anda menguji manajer keamanan / mekanisme pengujian.
Bill K
6
Pastikan teardown dijalankan dengan benar, jika tidak, pengujian Anda akan gagal pada pelari seperti Eclipse karena aplikasi JUnit tidak dapat keluar! :)
MetroidFan2002
6
Saya tidak suka solusi menggunakan manajer keamanan. Sepertinya hack bagi saya hanya untuk mengujinya.
Nicolai Reuschling
6
Jika Anda menggunakan junit 4.7 atau lebih tinggi, biarkan perpustakaan menangani dengan menangkap panggilan System.exit Anda. Aturan Sistem - stefanbirkner.github.com/system-rules
Will
6
"Alih-alih mengakhiri dengan System.exit (whateverValue), mengapa tidak membuang pengecualian yang tidak dicentang?" - karena saya menggunakan kerangka pemrosesan argumen baris perintah yang memanggil System.exitkapan saja argumen baris perintah yang tidak valid diberikan.
Adam Parkin
107

Pustaka Aturan Sistem memiliki aturan JUnit yang disebut ExpectedSystemExit. Dengan aturan ini Anda dapat menguji kode, yang memanggil System.exit (...):

public void MyTest {
    @Rule
    public final ExpectedSystemExit exit = ExpectedSystemExit.none();

    @Test
    public void systemExitWithArbitraryStatusCode() {
        exit.expectSystemExit();
        //the code under test, which calls System.exit(...);
    }

    @Test
    public void systemExitWithSelectedStatusCode0() {
        exit.expectSystemExitWithStatus(0);
        //the code under test, which calls System.exit(0);
    }
}

Pengungkapan penuh: Saya penulis perpustakaan itu.

Stefan Birkner
sumber
3
Sempurna. Anggun. Tidak perlu mengubah tusuk kode asli saya atau bermain-main dengan manajer keamanan. Ini harus menjadi jawaban teratas!
Akan
2
Ini harus menjadi jawaban teratas. Alih-alih perdebatan tanpa akhir tentang penggunaan yang tepat dari System.exit, langsung ke intinya. Selain itu, solusi fleksibel dalam kepatuhan terhadap JUnit itu sendiri sehingga kita tidak perlu menemukan kembali roda atau mengacaukan manajer keamanan.
L. Holanda
@LeoHolanda Apakah solusi ini tidak mengalami "masalah" yang sama dengan yang Anda gunakan untuk membenarkan downvote pada jawaban saya? Juga, bagaimana dengan pengguna TestNG?
Rogério
2
@LeoHolanda Anda benar; melihat implementasi aturan, saya sekarang melihatnya menggunakan manajer keamanan khusus yang melempar pengecualian ketika panggilan untuk cek "keluar sistem" terjadi, oleh karena itu mengakhiri tes. Contoh uji tambahan dalam jawaban saya memenuhi kedua persyaratan (verifikasi yang tepat dengan System.exit dipanggil / tidak dipanggil), BTW. Penggunaannya ExpectedSystemRulebagus, tentu saja; masalahnya adalah membutuhkan perpustakaan pihak ketiga tambahan yang menyediakan sangat sedikit dalam hal kegunaan dunia nyata, dan spesifik JUnit.
Rogério
2
Ada exit.checkAssertionAfterwards().
Stefan Birkner
31

Bagaimana dengan menyuntikkan "ExitManager" ke dalam Metode ini:

public interface ExitManager {
    void exit(int exitCode);
}

public class ExitManagerImpl implements ExitManager {
    public void exit(int exitCode) {
        System.exit(exitCode);
    }
}

public class ExitManagerMock implements ExitManager {
    public bool exitWasCalled;
    public int exitCode;
    public void exit(int exitCode) {
        exitWasCalled = true;
        this.exitCode = exitCode;
    }
}

public class MethodsCallExit {
    public void CallsExit(ExitManager exitManager) {
        // whatever
        if (foo) {
            exitManager.exit(42);
        }
        // whatever
    }
}

Kode produksi menggunakan ExitManagerImpl dan kode tes menggunakan ExitManagerMock dan dapat memeriksa apakah exit () dipanggil dan dengan kode keluar mana.

EricSchaefer
sumber
1
+1 Solusi yang bagus. Juga mudah diimplementasikan jika Anda menggunakan Pegas saat ExitManager menjadi Komponen sederhana. Perlu diketahui bahwa Anda perlu memastikan bahwa kode Anda tidak dapat dijalankan setelah panggilan exitManager.exit (). Ketika kode Anda sedang diuji dengan ExitManager tiruan kode itu tidak akan benar-benar keluar setelah panggilan untuk keluarManager.exit.
Joman68
31

Anda sebenarnya dapat mengejek atau mematikan System.exitmetodenya, dalam tes JUnit.

Misalnya, menggunakan JMockit Anda dapat menulis (ada juga cara lain):

@Test
public void mockSystemExit(@Mocked("exit") System mockSystem)
{
    // Called by code under test:
    System.exit(); // will not exit the program
}


EDIT: Tes alternatif (menggunakan JMockit API terbaru) yang tidak memungkinkan kode untuk dijalankan setelah panggilan ke System.exit(n):

@Test(expected = EOFException.class)
public void checkingForSystemExitWhileNotAllowingCodeToContinueToRun() {
    new Expectations(System.class) {{ System.exit(anyInt); result = new EOFException(); }};

    // From the code under test:
    System.exit(1);
    System.out.println("This will never run (and not exit either)");
}
Rogério
sumber
2
Pilih alasan: Masalah dengan solusi ini adalah bahwa jika System.exit bukan baris terakhir dalam kode (yaitu di dalam kondisi jika), kode akan terus berjalan.
L. Holanda
@LeoHolanda Menambahkan versi tes yang mencegah kode untuk berjalan setelah exitpanggilan (bukan bahwa itu benar-benar masalah, IMO).
Rogério
Mungkinkah lebih tepat untuk mengganti System.out.println () terakhir dengan pernyataan tegas?
user515655
"@Mocked (" exit ")" tampaknya tidak berfungsi lagi dengan JMockit 1.43: "Nilai atribut tidak terdefinisi untuk tipe penjelasan Mocked" Docs: "Ada tiga anotasi mengejek yang dapat kita gunakan ketika mendeklarasikan bidang tiruan dan parameter: @Mocked, yang akan mengolok-olok semua metode dan konstruktor pada semua instance kelas mocked yang ada dan yang akan datang (untuk durasi tes yang menggunakannya); " jmockit.github.io/tutorial/Mocking.html#mocked
Thorsten Schöning
Apakah Anda benar-benar mencoba saran Anda? Saya mendapatkan: "java.lang.IllegalArgumentException: Kelas java.lang.System tidak Runtimedapat diejek " dapat diejek, tetapi tidak berhenti System.exitsetidaknya dalam skenario saya menjalankan Tes di Gradle.
Thorsten Schöning
20

Salah satu trik yang kami gunakan dalam basis kode kami adalah membuat panggilan ke System.exit () dienkapsulasi dalam imp Runnable, yang metode yang dimaksud digunakan secara default. Untuk pengujian unit, kami menetapkan Runnable tiruan yang berbeda. Sesuatu seperti ini:

private static final Runnable DEFAULT_ACTION = new Runnable(){
  public void run(){
    System.exit(0);
  }
};

public void foo(){ 
  this.foo(DEFAULT_ACTION);
}

/* package-visible only for unit testing */
void foo(Runnable action){   
  // ...some stuff...   
  action.run(); 
}

... dan metode uji JUnit ...

public void testFoo(){   
  final AtomicBoolean actionWasCalled = new AtomicBoolean(false);   
  fooObject.foo(new Runnable(){
    public void run(){
      actionWasCalled.set(true);
    }   
  });   
  assertTrue(actionWasCalled.get()); 
}
Scott Bale
sumber
Apakah ini yang mereka sebut injeksi ketergantungan?
Thomas Ahle
2
Contoh ini seperti yang ditulis adalah semacam injeksi ketergantungan setengah dipanggang - ketergantungan dilewatkan ke metode foo paket-terlihat (baik dengan metode foo publik atau uji unit), tetapi kelas utama masih hardcodes implementasi Runnable default.
Scott Bale
6

Buat kelas mock-mampu yang membungkus System.exit ()

Saya setuju dengan EricSchaefer . Tetapi jika Anda menggunakan kerangka kerja mocking yang baik seperti Mockito kelas beton sederhana sudah cukup, tidak perlu untuk antarmuka dan dua implementasi.

Menghentikan eksekusi tes pada System.exit ()

Masalah:

// do thing1
if(someCondition) {
    System.exit(1);
}
// do thing2
System.exit(0)

Mocked Sytem.exit()tidak akan menghentikan eksekusi. Ini buruk jika Anda ingin menguji yang thing2tidak dieksekusi.

Larutan:

Anda harus memperbaiki kode ini seperti yang disarankan oleh martin :

// do thing1
if(someCondition) {
    return 1;
}
// do thing2
return 0;

Dan lakukan System.exit(status)dalam fungsi panggilan. Ini memaksa Anda untuk memiliki semua milik Anda System.exit()di satu tempat di atau dekat main(). Ini lebih bersih daripada memanggil System.exit()jauh ke dalam logika Anda.

Kode

Pembungkus:

public class SystemExit {

    public void exit(int status) {
        System.exit(status);
    }
}

Utama:

public class Main {

    private final SystemExit systemExit;


    Main(SystemExit systemExit) {
        this.systemExit = systemExit;
    }


    public static void main(String[] args) {
        SystemExit aSystemExit = new SystemExit();
        Main main = new Main(aSystemExit);

        main.executeAndExit(args);
    }


    void executeAndExit(String[] args) {
        int status = execute(args);
        systemExit.exit(status);
    }


    private int execute(String[] args) {
        System.out.println("First argument:");
        if (args.length == 0) {
            return 1;
        }
        System.out.println(args[0]);
        return 0;
    }
}

Uji:

public class MainTest {

    private Main       main;

    private SystemExit systemExit;


    @Before
    public void setUp() {
        systemExit = mock(SystemExit.class);
        main = new Main(systemExit);
    }


    @Test
    public void executeCallsSystemExit() {
        String[] emptyArgs = {};

        // test
        main.executeAndExit(emptyArgs);

        verify(systemExit).exit(1);
    }
}
Arend v. Reinersdorff
sumber
5

Saya suka beberapa jawaban yang sudah diberikan tetapi saya ingin menunjukkan teknik berbeda yang sering berguna ketika mendapatkan kode lama yang diuji. Kode yang diberikan seperti:

public class Foo {
  public void bar(int i) {
    if (i < 0) {
      System.exit(i);
    }
  }
}

Anda dapat melakukan refactoring yang aman untuk membuat metode yang membungkus panggilan System.exit:

public class Foo {
  public void bar(int i) {
    if (i < 0) {
      exit(i);
    }
  }

  void exit(int i) {
    System.exit(i);
  }
}

Kemudian Anda dapat membuat palsu untuk pengujian Anda yang menimpa keluar:

public class TestFoo extends TestCase {

  public void testShouldExitWithNegativeNumbers() {
    TestFoo foo = new TestFoo();
    foo.bar(-1);
    assertTrue(foo.exitCalled);
    assertEquals(-1, foo.exitValue);
  }

  private class TestFoo extends Foo {
    boolean exitCalled;
    int exitValue;
    void exit(int i) {
      exitCalled = true;
      exitValue = i;
    }
}

Ini adalah teknik generik untuk menggantikan perilaku untuk kasus uji, dan saya menggunakannya sepanjang waktu ketika refactoring kode lama. Biasanya tidak di mana saya akan meninggalkan sesuatu, tetapi langkah menengah untuk mendapatkan kode yang ada di bawah tes.

Jeffrey Fredrick
sumber
2
Teknik ini tidak menghentikan aliran conrol ketika exit () telah dipanggil. Gunakan Pengecualian sebagai gantinya.
Andrea Francia
3

Pandangan cepat pada api, menunjukkan bahwa System.exit dapat melempar pengecualian esp. jika seorang manajer keamanan melarang penutupan vm. Mungkin solusinya adalah menginstal manajer seperti itu.

flolo
sumber
3

Anda dapat menggunakan java SecurityManager untuk mencegah utas saat ini dari mematikan Java VM. Kode berikut harus melakukan apa yang Anda inginkan:

SecurityManager securityManager = new SecurityManager() {
    public void checkPermission(Permission permission) {
        if ("exitVM".equals(permission.getName())) {
            throw new SecurityException("System.exit attempted and blocked.");
        }
    }
};
System.setSecurityManager(securityManager);
Marc Novakowski
sumber
Hm Dokumen System.exit mengatakan secara spesifik bahwa checkExit (int) akan dipanggil, bukan checkPermission dengan name = "exitVM". Saya ingin tahu apakah saya harus mengganti keduanya?
Chris Conway
Nama izin sebenarnya adalah exitVM. (Statuscode), yaitu exitVM.0 - setidaknya dalam pengujian saya baru-baru ini di OSX.
Mark Derricutt
3

Agar jawaban VonC berjalan pada JUnit 4, saya telah memodifikasi kodenya sebagai berikut

protected static class ExitException extends SecurityException {
    private static final long serialVersionUID = -1982617086752946683L;
    public final int status;

    public ExitException(int status) {
        super("There is no escape!");
        this.status = status;
    }
}

private static class NoExitSecurityManager extends SecurityManager {
    @Override
    public void checkPermission(Permission perm) {
        // allow anything.
    }

    @Override
    public void checkPermission(Permission perm, Object context) {
        // allow anything.
    }

    @Override
    public void checkExit(int status) {
        super.checkExit(status);
        throw new ExitException(status);
    }
}

private SecurityManager securityManager;

@Before
public void setUp() {
    securityManager = System.getSecurityManager();
    System.setSecurityManager(new NoExitSecurityManager());
}

@After
public void tearDown() {
    System.setSecurityManager(securityManager);
}
Jeow Li Huan
sumber
3

Anda dapat menguji System.exit (..) dengan mengganti instance Runtime. Misalnya dengan TestNG + Mockito:

public class ConsoleTest {
    /** Original runtime. */
    private Runtime originalRuntime;

    /** Mocked runtime. */
    private Runtime spyRuntime;

    @BeforeMethod
    public void setUp() {
        originalRuntime = Runtime.getRuntime();
        spyRuntime = spy(originalRuntime);

        // Replace original runtime with a spy (via reflection).
        Utils.setField(Runtime.class, "currentRuntime", spyRuntime);
    }

    @AfterMethod
    public void tearDown() {
        // Recover original runtime.
        Utils.setField(Runtime.class, "currentRuntime", originalRuntime);
    }

    @Test
    public void testSystemExit() {
        // Or anything you want as an answer.
        doNothing().when(spyRuntime).exit(anyInt());

        System.exit(1);

        verify(spyRuntime).exit(1);
    }
}
ursa
sumber
2

Ada lingkungan di mana kode keluar yang dikembalikan digunakan oleh program panggilan (seperti ERRORLEVEL di MS Batch). Kami memiliki tes di sekitar metode utama yang melakukan ini dalam kode kami, dan pendekatan kami telah menggunakan penggantian SecurityManager yang sama seperti yang digunakan dalam tes lain di sini.

Tadi malam saya mengumpulkan JAR kecil menggunakan penjelasan Junit @Rule untuk menyembunyikan kode manajer keamanan, serta menambahkan harapan berdasarkan kode pengembalian yang diharapkan. http://code.google.com/p/junitsystemrules/

Dan Watt
sumber
2

Sebagian besar solusi akan melakukannya

  • hentikan tes (metode, bukan seluruh proses) saat System.exit()ini disebut
  • abaikan yang sudah diinstal SecurityManager
  • Terkadang cukup spesifik untuk kerangka uji
  • batasi untuk digunakan maksimal satu kali per test case

Dengan demikian, sebagian besar solusi tidak cocok untuk situasi di mana:

  • Verifikasi efek samping harus dilakukan setelah panggilan ke System.exit()
  • Manajer keamanan yang ada adalah bagian dari pengujian.
  • Kerangka uji yang berbeda digunakan.
  • Anda ingin memiliki beberapa verifikasi dalam satu test case. Ini mungkin sangat tidak dianjurkan, tetapi bisa sangat nyaman di kali, terutama dalam kombinasi dengan assertAll(), misalnya.

Saya tidak senang dengan pembatasan yang diberlakukan oleh solusi yang ada yang disajikan dalam jawaban lain, dan dengan demikian muncul dengan sesuatu sendiri.

Kelas berikut menyediakan metode assertExits(int expectedStatus, Executable executable)yang menyatakan bahwa System.exit()dipanggil dengan statusnilai yang ditentukan , dan tes dapat dilanjutkan setelahnya. Ini bekerja dengan cara yang sama seperti JUnit 5assertThrows . Itu juga menghormati manajer keamanan yang ada.

Ada satu masalah yang tersisa: Ketika kode yang diuji menginstal manajer keamanan baru yang sepenuhnya menggantikan manajer keamanan yang ditetapkan oleh tes. Semua SecurityManagersolusi berbasis lainnya yang saya kenal menderita masalah yang sama.

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

Anda dapat menggunakan kelas seperti ini:

    @Test
    void example() {
        assertExits(0, () -> System.exit(0)); // succeeds
        assertExits(1, () -> System.exit(1)); // succeeds
        assertExits(2, () -> System.exit(1)); // fails
    }

Kode dapat dengan mudah porting ke JUnit 4, TestNG, atau kerangka kerja lainnya, jika perlu. Satu-satunya elemen kerangka spesifik gagal tes. Ini dapat dengan mudah diubah menjadi sesuatu yang independen kerangka kerja (selain Junit 4 Rule

Ada ruang untuk perbaikan, misalnya, kelebihan muatan assertExits()dengan pesan yang dapat disesuaikan.

Christian Hujer
sumber
1

Gunakan Runtime.exec(String command)untuk memulai JVM dalam proses terpisah.

Alexei
sumber
3
Bagaimana Anda akan berinteraksi dengan kelas yang diuji, jika sedang dalam proses terpisah dari tes unit?
DNA
1
Dalam 99% kasus, System.exit ada di dalam metode utama. Oleh karena itu, Anda berinteraksi dengan mereka dengan argumen baris perintah (yaitu argumen).
L. Holanda
1

Ada masalah kecil dengan SecurityManagersolusinya. Beberapa metode, seperti JFrame.exitOnClose, juga meneleponSecurityManager.checkExit . Dalam aplikasi saya, saya tidak ingin panggilan itu gagal, jadi saya gunakan

Class[] stack = getClassContext();
if (stack[1] != JFrame.class && !okToExit) throw new ExitException();
super.checkExit(status);
cayhorstmann
sumber
0

Memanggil System.exit () adalah praktik yang buruk, kecuali itu dilakukan di dalam main (). Metode-metode ini harus membuang pengecualian yang, pada akhirnya, ditangkap oleh main Anda (), yang kemudian memanggil System.exit dengan kode yang sesuai.


sumber
8
Tapi itu tidak menjawab pertanyaan. Bagaimana jika fungsi yang diuji IS pada akhirnya merupakan metode utama? Jadi memanggil System.exit () mungkin valid dan ok dari perspektif desain. Bagaimana Anda menulis test case untuk itu?
Elie
3
Anda tidak perlu menguji metode utama karena metode utama hanya perlu mengambil argumen, meneruskannya ke metode parser, dan kemudian mulai menjalankan aplikasi. Seharusnya tidak ada logika dalam metode utama yang akan diuji.
Thomas Owens
5
@ Elie: Dalam jenis pertanyaan ini ada dua jawaban yang valid. Satu menjawab pertanyaan yang diajukan, dan satu bertanya mengapa pertanyaan itu didasarkan. Kedua jenis jawaban ini memberikan pemahaman yang lebih baik, dan terutama keduanya secara bersamaan.
runaros