単体テストと統合テストに使用できる一般的に有用なアプローチは、 run() および exit() メソッドを提供するパッケージ プライベート (デフォルト アクセス) のモック可能なランナー クラスを使用することです。これらのメソッドは、テスト モジュールの Mock または Fake テスト クラスによってオーバーライドできます。
テスト クラス (JUnit またはその他) は、exit() メソッドが System.exit() の代わりにスローできる例外を提供します。
package mainmocked;
class MainRunner {
void run(final String[] args) {
new MainMocked().run(args);
}
void exit(final int status) {
System.exit(status);
}
}
以下の main() を含むクラスには、ユニットまたは統合テスト時にモックまたは偽のランナーを受け取る altMain() もあります。
package mainmocked;
public class MainMocked {
private static MainRunner runner = new MainRunner();
static void altMain(final String[] args, final MainRunner inRunner) {
runner = inRunner;
main(args);
}
public static void main(String[] args) {
try {
runner.run(args);
} catch (Throwable ex) {
// Log("error: ", ex);
runner.exit(1);
}
runner.exit(0);
} // main
public void run(String[] args) {
// do things ...
}
} // class
シンプルなモック (Mockito を使用) は次のようになります。
@Test
public void testAltMain() {
String[] args0 = {};
MainRunner mockRunner = mock(MainRunner.class);
MainMocked.altMain(args0, mockRunner);
verify(mockRunner).run(args0);
verify(mockRunner).exit(0);
}
より複雑なテスト クラスでは、run() で何でもできる Fake と、System.exit() を置き換える Exception クラスを使用します。
private class FakeRunnerRuns extends MainRunner {
@Override
void run(String[] args){
new MainMocked().run(args);
}
@Override
void exit(final int status) {
if (status == 0) {
throw new MyMockExitExceptionOK("exit(0) success");
}
else {
throw new MyMockExitExceptionFail("Unexpected Exception");
} // ok
} // exit
} // class