জাভা: System.exit () কল করে এমন পদ্ধতিগুলি কীভাবে পরীক্ষা করবেন?


198

আমি কয়েকটি পদ্ধতি পেয়েছি যা System.exit()নির্দিষ্ট ইনপুটগুলিতে কল করা উচিত । দুর্ভাগ্যক্রমে, এই কেসগুলি পরীক্ষার ফলে JUnit সমাপ্ত হতে পারে! কোনও নতুন থ্রেডে পদ্ধতি কল করা সাহায্য করবে বলে মনে হয় না, যেহেতু System.exit()কেবলমাত্র বর্তমান থ্রেড নয়, জেভিএমকে সমাপ্ত করে। এটি মোকাবেলার জন্য কি কোনও সাধারণ প্যাটার্ন রয়েছে? উদাহরণস্বরূপ, আমি কি স্টাবের জন্য সাবস্ক্রিপশন করতে পারি System.exit()?

[সম্পাদনা] প্রশ্নে ক্লাসটি আসলে একটি কমান্ড-লাইন সরঞ্জাম যা আমি ইউএনইটের ভিতরে পরীক্ষা করার চেষ্টা করছি। সম্ভবত JUnit কাজটির জন্য সঠিক সরঞ্জাম নয়? পরিপূরক রিগ্রেশন টেস্টিং সরঞ্জামগুলির জন্য পরামর্শগুলি স্বাগত ((সম্ভবত এমন কিছু যা JUnit এবং EclEmma এর সাথে ভালভাবে সংহত হয়)।


2
আমি কৌতূহলী ছিলাম যে কোনও ফাংশন কখনই সিস্টেম.এক্সিটকে কল করবে ...)
টমাস ওয়ানস

2
আপনি যদি এমন কোনও ফাংশন কল করছেন যা অ্যাপ্লিকেশনটি প্রস্থান করে। উদাহরণস্বরূপ, যদি ব্যবহারকারী কোনও টাস্ক সম্পাদন করার চেষ্টা করে তবে তারা একের পর এক x বার আরও বেশি সম্পাদন করার অনুমতিপ্রাপ্ত নয়, আপনি এটিকে অ্যাপ্লিকেশন থেকে জোর করে বের করে দিন।
এলি

5
আমি এখনও মনে করি যে সেক্ষেত্রে অ্যাপ্লিকেশন থেকে System.exit () এর পরিবর্তে ফিরে যাওয়ার আরও ভাল উপায় হওয়া উচিত।
টমাস ওভেন

27
আপনি যদি মেইন () পরীক্ষা করে থাকেন তবে সিস্টেম.এক্সিট () নাম্বারে কল করার উপযুক্ত ধারণা তৈরি হয়। আমাদের একটি প্রয়োজনীয়তা রয়েছে যে ত্রুটিতে কোনও ব্যাচ প্রক্রিয়াটি 1 দিয়ে এবং সাফল্যের সাথে প্রস্থান করতে 0 দিয়ে বের হওয়া উচিত
ম্যাথু ফারওয়েল

5
যারা System.exit()খারাপ বলেছেন তাদের সাথে আমি একমত নই - আপনার প্রোগ্রামটি দ্রুত ব্যর্থ হওয়া উচিত। কোনও বিকাশ ছুঁড়ে ফেলা অবৈধ অবস্থায় কেবল কোনও অ্যাপ্লিকেশনকে দীর্ঘায়িত করে এমন পরিস্থিতিতে যেখানে কোনও বিকাশকারী প্রস্থান করতে চান এবং প্রবল ত্রুটি দেয়।
শ্রীধর সারনোবাত

উত্তর:


216

আসলে, ডার্কিলার ডট কম পরামর্শ দেয়:

  • কেন System.exit()?

System.exit (যাই হোক না কেন ভ্যালু) দিয়ে সমাপ্তির পরিবর্তে কেন একটি চেক করা ব্যতিক্রম নিক্ষেপ করবেন না? সাধারণ ব্যবহারে এটি জেভিএমের শেষ খাদের ক্যাচারের বাইরে চলে যেতে পারে এবং আপনার স্ক্রিপ্টটি বন্ধ করে দেবে (যদি না আপনি রাস্তায় কোথাও এটি ধরার সিদ্ধান্ত নেন, যা কোনও দিন কার্যকর হতে পারে)।

JUnit দৃশ্যে এটি JUnit কাঠামোর দ্বারা ধরা পড়বে, যে রিপোর্ট করবে যে এই ধরণের এবং এই জাতীয় পরীক্ষাটি ব্যর্থ হয়েছিল এবং পরের দিকে সহজেই অগ্রসর হবে।

  • আটকান System.exit()আসলে জেভিএম থেকে প্রস্থান করার জন্য:

সিকিউরিটি ম্যানেজারের সাথে চালানোর জন্য টেস্টকেসটি সংশোধন করার চেষ্টা করুন যা System.exit কল করা রোধ করে, তারপরে সিকিউরিটি এক্সসেপশন ধরুন।

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

ডিসেম্বর ২০১২ আপডেট করুন:

উইল প্রস্তাব মন্তব্য ব্যবহার সিস্টেম রুলস , JUnit একটি সংগ্রহ কোড যা ব্যবহারসমূহ পরীক্ষার জন্য (4.9+) নিয়ম java.lang.System
প্রথম দিকে এই বিষয়টি দ্বারা উল্লেখ করা হয়েছিল স্টিফান Birkner মধ্যে তার উত্তর ডিসেম্বর 2011 সালে।

System.exit(…)

যা বলা হয় ExpectedSystemExitতা যাচাই করতে নিয়মটি ব্যবহার করুন System.exit(…)
আপনি প্রস্থান স্থিতিটিও যাচাই করতে পারেন।

এই ক্ষেত্রে:

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

4
প্রথম উত্তরটি পছন্দ হয়নি তবে দ্বিতীয়টি খুব দুর্দান্ত - আমি সুরক্ষা পরিচালকদের সাথে গণ্ডগোল করিনি এবং ধরে নিয়েছিলাম যে তারা এর চেয়ে জটিল। তবে, আপনি কীভাবে সুরক্ষা পরিচালক / পরীক্ষার প্রক্রিয়া পরীক্ষা করেন।
বিল কে

6
টিয়ার ডাউনটি সঠিকভাবে সম্পাদিত হয়েছে তা নিশ্চিত করুন, অন্যথায়, আপনার পরীক্ষা গ্রহনের মতো রানার হিসাবে ব্যর্থ হবে কারণ JUnit অ্যাপ্লিকেশনটি প্রস্থান করতে পারে না! :)
MetroidFan2002

6
সিকিউরিটি ম্যানেজার ব্যবহার করে সমাধানটি পছন্দ করি না। এটি পরীক্ষা করার জন্য আমার কাছে হ্যাকের মতো মনে হচ্ছে।
নিকোলোই পুনঃচলিত

6
যদি আপনি জুনিয়ট ৪.7 বা তার বেশি ব্যবহার করে থাকেন তবে আপনার সিস্টেম.এক্সিট কলগুলি ক্যাপচার করার জন্য একটি লাইব্রেরি চুক্তি করুন। সিস্টেম বিধি - stefanbirkner.github.com/system-rules
উইল

6
"System.exit (যাই হোক না কেন ভ্যালু) দিয়ে সমাপ্তির পরিবর্তে, কেন একটি চেক করা ব্যতিক্রম ছোঁড়াবেন না?" - কারণ আমি কমান্ড লাইন আর্গুমেন্ট প্রসেসিং ফ্রেমওয়ার্ক ব্যবহার করছি যা System.exitযখনই কোনও অবৈধ কমান্ড লাইন আর্গুমেন্ট সরবরাহ করা হয় তখন কল করে ।
অ্যাডাম পার্কিন

106

লাইব্রেরি সিস্টেমের বিধিগুলিতে এক্সপেক্টডসিস্টেমএক্সিট নামে একটি JUnit নিয়ম রয়েছে। এই নিয়মের সাহায্যে আপনি কোডটি পরীক্ষা করতে সক্ষম হন, যা সিস্টেম.এক্সিটকে কল করে ... ()):

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

সম্পূর্ণ প্রকাশ: আমি সেই লাইব্রেরির লেখক।


3
পারফেক্ট। মার্জিত। আমার আসল কোডের কোনও সেলাই পরিবর্তন করতে বা সুরক্ষা ব্যবস্থাপকের সাথে ঘুরতে হবে না। এটি শীর্ষ উত্তর হতে হবে!
উইল

2
এটি শীর্ষ উত্তর হওয়া উচিত। System.exit এর সঠিক ব্যবহার সম্পর্কে অবিচ্ছিন্ন বিতর্কের পরিবর্তে সরাসরি বক্তব্য করুন। এছাড়াও, নিজেই JUnit মেনে চলা একটি নমনীয় সমাধান যাতে আমাদের চাকা পুনরায় উদ্বেগ বা সুরক্ষা ব্যবস্থাপকের সাথে গণ্ডগোলের প্রয়োজন হয় না।
এল। হল্যান্ড

@ লিওহোলান্ডা কি এই সমাধানটি একই "সমস্যার" দ্বারা ভুগছে না আপনি আমার উত্তরের ডাউনটকে ন্যায়সঙ্গত করতে বলেছিলেন? এছাড়াও, টেস্টএনজি ব্যবহারকারীদের সম্পর্কে কী?
Rogério

2
@ লেওহোলান্ডা আপনি ঠিক বলেছেন; নিয়মের বাস্তবায়নটির দিকে তাকিয়ে আমি এখন দেখতে পাচ্ছি এটি একটি কাস্টম সুরক্ষা ব্যবস্থাপক ব্যবহার করে যা "সিস্টেম প্রস্থান" পরীক্ষার জন্য কল আসে তখন একটি ব্যতিক্রম ছুঁড়ে দেয়, তাই পরীক্ষা শেষ করে। আমার উত্তরে যুক্ত উদাহরণ পরীক্ষা উভয় প্রয়োজনীয়তা পূরণ করে (সিস্টেম.এক্সিটের সাথে কল করা / বলা না হওয়ার সাথে সঠিক যাচাই), বিটিডাব্লু। এর ব্যবহার ExpectedSystemRuleঅবশ্যই দুর্দান্ত; সমস্যাটি হ'ল এর জন্য একটি অতিরিক্ত তৃতীয় পক্ষের লাইব্রেরি প্রয়োজন যা বাস্তব-জগতের দরকারীতার ক্ষেত্রে খুব কম সরবরাহ করে এবং এটি জুনিট-নির্দিষ্ট।
Rogério

2
আছে exit.checkAssertionAfterwards()
স্টেফান বার্কনার

31

এই পদ্ধতিতে "এক্সিটম্যানেজার" ইনজেকশন সম্পর্কে কীভাবে:

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

প্রোডাকশন কোডটি ExitManagerImpl ব্যবহার করে এবং পরীক্ষার কোডটি ExitManagerMock ব্যবহার করে এবং প্রস্থান () বলা হয়েছে এবং কোন প্রস্থান কোডের সাহায্যে তা পরীক্ষা করতে পারে।


1
+1 চমৎকার সমাধান। এক্সিটম্যানেজার একটি সাধারণ উপাদান হয়ে উঠলে আপনি বসন্তটি ব্যবহার করছেন যদি তা কার্যকর করাও সহজ। শুধু সচেতন থাকুন যে আপনার কোডটি প্রস্থানস্থানManager.exit () কল করার পরে কার্যকর হচ্ছে না তা নিশ্চিত করা দরকার। আপনার কোডটি যখন মক এক্সিটম্যানেজারের সাথে পরীক্ষা করা হচ্ছে তখন কোডটি বাস্তবে প্রস্থান করার জন্য কল ছাড়ার পরে প্রস্থান হবে না an
জোমান 68

31

আপনি জুনিত পরীক্ষায় প্রকৃতপক্ষে পদ্ধতিটিকে উপহাস বা হস্তান্তর করতে পারেনSystem.exit

উদাহরণস্বরূপ, জেমকিত ব্যবহার করে আপনি লিখতে পারেন (পাশাপাশি অন্যান্য উপায়ও রয়েছে):

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


সম্পাদনা: বিকল্প পরীক্ষা (সর্বশেষ জেএমকিত এপিআই ব্যবহার করে) যা কোনও কোডের পরে কোনও কোড চালানোর অনুমতি দেয় না 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)");
}

2
ভোটা ডাউন কারণ: এই সমাধানটির সাথে সমস্যাটি হ'ল যদি System.exit কোডের শেষ লাইন না হয় (যদি শর্তাবলীর ভিতরে থাকে তবে) কোডটি চলতে থাকবে।
এল। হল্যান্ডা

@ লিওহোল্যান্ডা পরীক্ষার একটি সংস্করণ যুক্ত করেছে যা exitকলটির পরে চালানো কোডটিকে বাধা দেয় (এটি আসলে কোনও সমস্যা ছিল না, আইএমও)।
Rogério

সর্বশেষ System.out.println () প্রতিস্থাপনের বিবৃতি দিয়ে প্রতিস্থাপন করা কি আরও উপযুক্ত হতে পারে?
ব্যবহারকারী515655

"@ মক্কেল (" প্রস্থান ")" জেএমকিত ১.৪৪ এর সাথে আর কাজ করবে বলে মনে হয় না: "এনকোটেশন ধরণের উপহাসের জন্য গুণকের মানটি নির্ধারিত নয়" দস্তাবেজগুলি: "মক ক্ষেত্রগুলি ঘোষণা করার সময় আমরা তিনটি পৃথক বিদ্রূপমূলক টীকা ব্যবহার করতে পারি এবং প্যারামিটারগুলি: @ মক্কেল, যা একটি উপহাসকৃত শ্রেণীর বিদ্যমান এবং ভবিষ্যতের সমস্ত দৃষ্টান্তে (এটি ব্যবহারের পরীক্ষার সময়কালের জন্য) সমস্ত পদ্ধতি এবং নির্মাতাকে উপহাস করবে; " jmockit.github.io/tutorial/Mocking.html#mocked
Thorsten Schöning

আপনি কি আসলেই আপনার পরামর্শটি চেষ্টা করেছিলেন? আমি পেয়েছি: "java.lang.IllegalArgumentException: Class java.lang.Sisstm is not mockable" Runtimeঠাট্টা করা যায়, তবে System.exitকমপক্ষে আমার দৃশ্যে গ্রেডলে টেস্ট চালানো থামায় না ।
থারস্টেন শেনিং

20

আমরা আমাদের কোড বেসে ব্যবহৃত একটি কৌশলটি ছিল সিস্টেম.এক্সিট () কে একটি রান রানযোগ্য ইমপ্লিটে এনপ্যাপুলেটেড করা, যা প্রশ্নে পদ্ধতিটি ডিফল্টরূপে ব্যবহৃত হয়। ইউনিট পরীক্ষার জন্য, আমরা একটি আলাদা মক রান্নেবল সেট করেছি। এটার মতো কিছু:

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

... এবং JUnit পরীক্ষা পদ্ধতি ...

public void testFoo(){   
  final AtomicBoolean actionWasCalled = new AtomicBoolean(false);   
  fooObject.foo(new Runnable(){
    public void run(){
      actionWasCalled.set(true);
    }   
  });   
  assertTrue(actionWasCalled.get()); 
}

এটিকে কি তারা নির্ভরতা ইঞ্জেকশন বলে?
টমাস আহলে

2
লিখিত হিসাবে এই উদাহরণটি অর্ধ-বেকড নির্ভরতা ইনজেকশন প্রকারের - নির্ভরতা প্যাকেজ-দৃশ্যমান foo পদ্ধতিতে পাস করা হয় (পাবলিক foo পদ্ধতি বা ইউনিট পরীক্ষার মাধ্যমে) তবে মূল শ্রেণি এখনও ডিফল্ট চালিতযোগ্য বাস্তবায়নকে হার্ডকোড করে।
স্কট বেল

6

মক-সক্ষম শ্রেণি তৈরি করুন যা System.exit () কে মোড় দেয়

আমি একমত EricSchaefer । তবে আপনি যদি মকিতোর মতো একটি ভাল উপহাসের কাঠামো ব্যবহার করেন তবে একটি সাধারণ কংক্রিট শ্রেণি যথেষ্ট, ইন্টারফেস এবং দুটি বাস্তবায়নের প্রয়োজন নেই।

System.exit () এ পরীক্ষা সম্পাদন বন্ধ করা হচ্ছে

সমস্যা:

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

একটি বিদ্রূপাত্মক Sytem.exit()কার্যকর কার্যকর হবে না। এটি thing2কার্যকর যদি আপনি পরীক্ষা করতে চান যা কার্যকর হয় না।

সমাধান:

মার্টিনের পরামর্শ অনুসারে আপনার এই কোডটি রিফ্যাক্টর করা উচিত :

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

এবং System.exit(status)কলিং ফাংশন করবেন। এই বাহিনী আপনি আপনার সমস্ত আছে System.exit()অথবা কাছাকাছি এক জায়গায় গুলি main()System.exit()আপনার যুক্তির ভিতরে গভীরভাবে কল করার চেয়ে এটি পরিষ্কার ।

কোড

আবরণ:

public class SystemExit {

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

প্রধান:

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

টেস্ট:

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

5

আমি ইতিমধ্যে প্রদত্ত কিছু উত্তর পছন্দ করি তবে আমি একটি ভিন্ন কৌশলটি প্রদর্শন করতে চেয়েছিলাম যা পরীক্ষার অধীনে উত্তরাধিকার কোড পাওয়ার সময় প্রায়শই কার্যকর। প্রদত্ত কোড:

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

সিস্টেম.এক্সিট কলটি মোড়কে এমন একটি পদ্ধতি তৈরি করতে আপনি একটি নিরাপদ রিফ্যাক্টরিং করতে পারেন:

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

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

তারপরে আপনি আপনার পরীক্ষার জন্য একটি জাল তৈরি করতে পারেন যা প্রস্থানটিকে ওভাররাইড করে:

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

এটি পরীক্ষার ক্ষেত্রে আচরণের বিকল্পের জন্য একটি জেনেরিক কৌশল এবং লিগ্যাসি কোডটি রিফ্যাক্টর করার সময় আমি এটি সমস্ত সময় ব্যবহার করি। এটি সাধারণত যেখানে আমি জিনিসটি ছেড়ে চলে যাচ্ছি তা নয়, তবে বিদ্যমান কোডটি পরীক্ষার অধীনে পেতে একটি মধ্যবর্তী পদক্ষেপ।


2
এই টেকনিউকগুলি প্রস্থানটি () ডেকে আনা হলে কনরোল প্রবাহকে থামায় না। পরিবর্তে একটি ব্যতিক্রম ব্যবহার করুন।
আন্দ্রে ফ্রান্সিয়া

3

এপিআইয়ের একটি তাত্ক্ষণিক দৃষ্টিভঙ্গি দেখায় যে System.exit একটি ব্যতিক্রম ছুঁড়ে ফেলতে পারে। যদি কোনও নিরাপত্তা ব্যবস্থাপনার ভিএম বন্ধ করতে নিষেধ করে। সম্ভবত একটি সমাধান হতে পারে এই জাতীয় পরিচালককে ইনস্টল করা।


3

আপনি বর্তমান থ্রেডটি জাভা ভিএম বন্ধ করতে বাধা রাখতে জাভা সিকিউরিটি ম্যানেজারটি ব্যবহার করতে পারেন। নিম্নলিখিত কোডটি আপনার যা করা উচিত তা করা উচিত:

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

হুঁ। সিস্টেম.এক্সিট ডক্সগুলি বিশেষত বলেছে যে চেকএক্সিট (ইনট) বলা হবে, = "প্রস্থানভিএম" নামের চেকপিরমিশন নয়। আমি ভাবছি আমার দুটোকেই ওভাররাইড করা উচিত কিনা?
ক্রিস কনওয়ে

অনুমতিটির নামটি আসলে বহির্গমন VM বলে মনে হচ্ছে status (স্ট্যাটাসকোড), অর্থাত্ એક્জিটভিএম.0 - কমপক্ষে ওএসএক্সে আমার সাম্প্রতিক পরীক্ষায়।
মার্ক ডেরিকট

3

ভনসির উত্তর 4 জুনে চালানোর জন্য, আমি কোডটি নিম্নরূপে সংশোধন করেছি

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

3

আপনি রানটাইম উদাহরণটি প্রতিস্থাপনের সাথে System.exit (..) পরীক্ষা করতে পারেন। যেমন টেস্টএনজি + মকিতো সহ:

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

2

এমন পরিবেশ রয়েছে যেখানে কলিং প্রোগ্রামের মাধ্যমে ফিরে আসা প্রস্থান কোডটি ব্যবহার করা হয় (যেমন এমএস ব্যাচে ERRORLEVEL যেমন)। আমাদের কোডগুলিতে এটি করে এমন প্রধান পদ্ধতিগুলির চারপাশে আমাদের পরীক্ষা রয়েছে এবং আমাদের পদ্ধতির এখানে অন্যান্য পরীক্ষাগুলিতে ব্যবহৃত অনুরূপ সিকিউরিটি ম্যানেজার ওভাররাইড ব্যবহার করা হয়েছে।

সুরক্ষা ব্যবস্থাপক কোডটি গোপন করতে জুনিত @ রুল এনোটেশনগুলি ব্যবহার করে গত রাতে আমি একটি ছোট জেআর একসাথে রেখেছি, পাশাপাশি প্রত্যাশিত রিটার্ন কোডের ভিত্তিতে প্রত্যাশা যুক্ত করেছি। http://code.google.com/p/junitsystemrules/


2

সর্বাধিক সমাধান হবে

  • পরীক্ষাটি শেষ করুন (পদ্ধতিটি, পুরো রান নয়) মুহুর্তটি System.exit()বলা হয়
  • ইতিমধ্যে ইনস্টল করা উপেক্ষা করুন SecurityManager
  • কখনও কখনও একটি পরীক্ষার কাঠামোর সাথে বেশ সুনির্দিষ্ট হতে হবে
  • প্রতি পরীক্ষার ক্ষেত্রে একবারে সর্বোচ্চ ব্যবহার করতে সীমাবদ্ধ করুন

সুতরাং, বেশিরভাগ সমাধান পরিস্থিতিগুলির জন্য উপযুক্ত নয় যেখানে:

  • পার্শ্ব প্রতিক্রিয়া যাচাইকরণ কল করার পরে করা উচিত System.exit()
  • একটি বিদ্যমান সুরক্ষা পরিচালক পরীক্ষার অংশ।
  • একটি ভিন্ন পরীক্ষার কাঠামো ব্যবহৃত হয়।
  • আপনি একটি একক পরীক্ষার ক্ষেত্রে একাধিক যাচাইকরণ থাকতে চান। এটি কঠোরভাবে সুপারিশ করা হতে পারে না, তবে এটি অনেক সময় খুব সুবিধাজনক হতে পারে, বিশেষত এর মিশ্রণে assertAll(), উদাহরণস্বরূপ।

অন্যান্য উত্তরে উপস্থাপিত বিদ্যমান সমাধানগুলির দ্বারা আরোপিত নিষেধাজ্ঞাগুলি নিয়ে আমি সন্তুষ্ট নই এবং এইভাবে আমি নিজেই কিছু নিয়ে এসেছি।

নিম্নলিখিত ক্লাসটি এমন একটি পদ্ধতি সরবরাহ করে assertExits(int expectedStatus, Executable executable)যা দাবি করে যে System.exit()নির্দিষ্ট statusমান সহ ডাকা হয় এবং তার পরে পরীক্ষাটি চালিয়ে যেতে পারে। এটি JUnit 5 এর মতোই কাজ করে 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, বা অন্য কোনও কাঠামোতে পোর্ট করা যেতে পারে। একমাত্র ফ্রেমওয়ার্ক-নির্দিষ্ট উপাদান পরীক্ষায় ব্যর্থ হচ্ছে। এটি সহজেই ফ্রেমওয়ার্ক-স্বাধীন কিছুতে পরিবর্তন করা যেতে পারে ( জুনিট 4 বাদে) Rule

উন্নতির জন্য জায়গা রয়েছে, উদাহরণস্বরূপ, assertExits()কাস্টমাইজযোগ্য বার্তাগুলি দিয়ে ওভারলোডিং ।


1

Runtime.exec(String command)পৃথক প্রক্রিয়াতে জেভিএম শুরু করতে ব্যবহার করুন ।


3
আপনি ইউনিটের পরীক্ষা থেকে পৃথক প্রক্রিয়াতে থাকলে পরীক্ষার অধীনে শ্রেণীর সাথে কীভাবে যোগাযোগ করবেন?
ডিএনএ

1
99% ক্ষেত্রে System.exit একটি মূল পদ্ধতির অভ্যন্তরে। অতএব, আপনি কমান্ড লাইন আর্গুমেন্ট (অর্থাত্ অর্গগুলি) দ্বারা তাদের সাথে যোগাযোগ করুন।
এল। হল্যান্ডা

1

সমাধানের সাথে একটি ছোটখাটো সমস্যা আছে SecurityManager। কিছু পদ্ধতি যেমন JFrame.exitOnCloseকল করে SecurityManager.checkExit। আমার অ্যাপ্লিকেশনটিতে, আমি কলটি ব্যর্থ হতে চাইনি, তাই আমি ব্যবহার করেছি

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

0

কলিং সিস্টেম.এক্সিট () একটি খারাপ অভ্যাস, যদি না এটি একটি মূল () এর অভ্যন্তরে সম্পন্ন হয়। এই পদ্ধতিগুলি এমন একটি ব্যতিক্রম ছুঁড়ে ফেলা উচিত যা শেষ পর্যন্ত আপনার মূল () দ্বারা ধরা পড়ে, যিনি পরে উপযুক্ত কোডের সাথে System.exit কল করেন।


8
যদিও এই প্রশ্নের উত্তর দেয় না। যদি ফাংশনটি পরীক্ষা করা হয় তবে শেষ পর্যন্ত মূল পদ্ধতিটি হয়? সুতরাং System.exit () কল করা কোনও ডিজাইনের দৃষ্টিকোণ থেকে বৈধ এবং ঠিক আছে। আপনি কিভাবে এটির জন্য একটি পরীক্ষার কেস লিখবেন?
এলি

3
আপনাকে মূল পদ্ধতিটি পরীক্ষা করতে হবে না কারণ মূল পদ্ধতিটিতে কেবল কোনও যুক্তি নেওয়া উচিত, সেগুলি পার্সার পদ্ধতিতে প্রেরণ করা উচিত এবং তারপরে অ্যাপ্লিকেশনটি শুরু করুন। মূল পদ্ধতিতে পরীক্ষা করার কোনও যুক্তি থাকতে হবে না।
টমাস

5
@ এলি: এই ধরণের প্রশ্নের মধ্যে দুটি বৈধ উত্তর রয়েছে। একজন জিজ্ঞাসা করা প্রশ্নের উত্তর দিয়েছিলেন এবং কেউ জিজ্ঞাসা করছেন কেন ভিত্তি করা হয়েছিল। উভয় প্রকারের উত্তরগুলি আরও ভাল বোঝা দেয় এবং বিশেষত দু'জনেই একত্রে।
রানারোস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.