जूनिट - रन सेट अप विधि एक बार


119

मैंने परीक्षण के एक जोड़े के साथ एक कक्षा स्थापित की और उपयोग करने के बजाय @Beforeमैं एक सेटअप विधि रखना चाहूंगा जो सभी परीक्षणों से पहले केवल एक बार निष्पादित हो। क्या यह संभव है जुनित 4.8 के साथ?


1
RunListener पर एक नज़र डालें: stackoverflow.com/a/14773170/548473
ग्रिगोरी किसलिन

जवाबों:


205

हालांकि मैं @assylias से सहमत हूं कि उपयोग @BeforeClassकरना एक क्लासिक समाधान है यह हमेशा सुविधाजनक नहीं होता है। विधि के साथ एनोटेट @BeforeClassस्थिर होना चाहिए। यह कुछ परीक्षणों के लिए बहुत असुविधाजनक है जिन्हें परीक्षण मामले की आवश्यकता है। उदाहरण के लिए वसंत आधारित परीक्षण जो @Autowiredवसंत संदर्भ में परिभाषित सेवाओं के साथ काम करने के लिए उपयोग करते हैं।

इस मामले में मैं व्यक्तिगत रूप setUp()से @Beforeएनोटेशन के साथ एनोटेट की गई नियमित पद्धति का उपयोग करता हूं और अपने कस्टम static(!) booleanध्वज का प्रबंधन करता हूं :

private static boolean setUpIsDone = false;
.....
@Before
public void setUp() {
    if (setUpIsDone) {
        return;
    }
    // do the setup
    setUpIsDone = true;
}

10
केनी कैसन की टिप्पणी के साथ जोड़ना कि यह स्थिर क्यों होना चाहिए। यह स्थिर होना चाहिए क्योंकि JUnit प्रत्येक @Test विधि के लिए परीक्षण वर्ग का एक नया उदाहरण तुरंत देता है। यदि यह स्थिर नहीं है, तो उदाहरण चर को प्रत्येक उदाहरण के लिए डिफ़ॉल्ट मान (झूठा) पर रीसेट किया जाएगा। अधिक जानकारी के लिए देखें: martinfowler.com/bliki/JunitNewInstance.html
dustin.schultz

2
यह उस मामले को छोड़कर काम करता है जहां setUp()विधि एक सुपरक्लास में है - इसे हल करने के प्रयास के नीचे एक उत्तर पोस्ट किया है ।
स्टीव चेम्बर्स

4
मैं 84k प्रतिनिधि के साथ किसी से यह कहने में संकोच करता हूं, लेकिन इससे पहले कि वास्तव में प्रश्न का उत्तर दिया जाए: इससे पहले कि प्रत्येक टेस्ट क्लास की शुरुआत में चलाया जाता है। लेकिन ओपी ने एक के लिए कहा जो "सभी परीक्षणों से पहले केवल एक बार" चलता है। आपका प्रस्तावित समाधान ऐसा कर सकता है, लेकिन आपको अपनी सभी परीक्षण कक्षाओं को एक "कॉमनटेस्ट" वर्ग का विस्तार करना होगा ...
माइक कृंतक

1
@mikerodent, IMHO ओपी ने अपने परीक्षण के मामले में सभी परीक्षणों के बारे में पूछा, न कि सभी परीक्षण। तो, आपकी टिप्पणी कम प्रासंगिक है। BTW, किसी भी व्यक्ति को कुछ भी कहने की चिंता न करें भले ही उसकी प्रतिष्ठा अधिक हो। कम से कम मैं यही करता हूं :)। जब मैंने सवाल का जवाब दिया तो अगस्त 2012 में मेरी प्रतिष्ठा काफी कम थी।
एलेक्सआर

मेरे मामले में काम नहीं करता है, सेटअप में आरंभ किए गए चर को प्रत्येक परीक्षण के बाद रीसेट किया जाता है, इसलिए यह केवल एक बार init के लिए व्यर्थ है।
एपेक्स

89

आप उपयोग कर सकते हैं एनोटेशन :BeforeClass

@BeforeClass
public static void setUpClass() {
    //executed only once, before the first test
}

12
मैं इसका उपयोग नहीं कर सकता, मेरे पास कुछ सेटअप विधियाँ हैं जो गैर-स्थैतिक घटकों जैसे
गेटक्लास

1
@ Bober02 इससे पहले कि वास्तव में स्थिर होने की जरूरत है। यदि आप उसका उपयोग नहीं कर सकते हैं, तो दूसरा उत्तर वर्कअराउंड प्रदान करता है।
अस्तिलास

2
सुनिश्चित करें कि आप TheClassYouWant.classअपने getClass () कॉल के बजाय उपयोग नहीं कर सकते हैं ? यह वास्तविक जावा है String.class.getName():।
स्टॉल्सविक


1
@mikerodent मैंने प्रश्न को "कक्षा में सभी परीक्षण" के रूप में समझा - लेकिन आप सही हैं कि यह वही हो सकता है जो ओपी चाहता था।
अस्वलीज १५'१

29

JUnit 5 में अब एक @BeforeAll एनोटेशन है:

यह दर्शाता है कि वर्तमान वर्ग या वर्ग पदानुक्रम में एनोटेट पद्धति को सभी @ तरीकों से पहले निष्पादित किया जाना चाहिए; JUnit 4 के @BeforeClass के अनुरूप है। ऐसे तरीके स्थिर होने चाहिए।

JUnit 5 के जीवनचक्र एनोटेशन से लगता है कि अंत में यह सही हो गया है! आप अनुमान लगा सकते हैं कि कौन से एनोटेशन बिना देखे भी उपलब्ध हैं (जैसे @BeforeEach @AfterAll)


6
यह वही समस्या है @BeforeClass, यह होने की जरूरत है static। IMO @ एलेक्सआर का समाधान अच्छे है।
zengr 19

@zengr आपसे सहमत हैं: जैसा कि मैंने एलेक्सर से कहा है, उनके समाधान के लिए सभी टेस्ट कक्षाओं को कॉमनटेस्ट क्लास से उप-वर्ग की आवश्यकता होती है, अगर यह केवल एक बार चलना है। लेकिन यह सरल है जितना आसान हो सकता है, और IMHO आप शायद "फैंसी" फ्रेमवर्क-आपूर्ति वाले समाधान का उपयोग न करें जब एक सरल तंत्र भाषा से उपलब्ध हो। जब तक पाठ्यक्रम का एक अच्छा कारण नहीं है। इसके अलावा, उसकी तरह एक साधारण चीज का उपयोग करते हुए, एक अच्छा के साथ "यह टिन पर" प्रकार का नाम क्या कहता है, पठनीयता के साथ मदद करता है।
माइक कृंतक

यह कहने के बाद, फिर से IMHO, "AfterAll" एनोटेशन होने के लिए बहुत अधिक औचित्य प्रतीत होता है: यह बहुत मुश्किल होगा और यह पता लगाने के लिए एक तंत्र को तैयार करने के लिए वंचित किया जाता है जब सभी परीक्षण किए गए थे। इसके विपरीत, निश्चित रूप से, शुद्धतावादी शायद यह कहने जा रहे हैं कि आपको कभी भी "अंतिम सफाई" नहीं करनी चाहिए, अर्थात प्रत्येक "अश्रु" को सभी संसाधनों को एक प्राचीन अवस्था में छोड़ देना चाहिए ... और वे शायद सही हैं!
माईक कृंतक

क्या यह मावेन के साथ काम करता है जहां कई मॉड्यूल हैं, प्रत्येक उनके परीक्षणों के साथ?
मार्क बून

@ मायिक कृंतक, मेरे मामले में प्रत्येक परीक्षण से पहले / बाद में फाइल सिस्टम में परीक्षण फाइलों को सेट करने और फाड़ने के बाद लगता है कि फाइलों पर गतिरोध चल रहा है। अभी के लिए, मैं एक बार स्थापित करने के लिए एलेक्सर के समाधान पर स्वतंत्र रूप से आया हूं। मेरे पास दो स्टैटिक फ्लैग हैं, पहले से ही सैटअप और डर्टी। सेटअप () कॉल सफाई () अगर एक गंदे राज्य शुरू में पता चला है, या अगर एक सेटअप विफलता एक गंदे राज्य की ओर जाता है। परीक्षण चलाने के बाद सफाई करने के लिए, मैं उन्हें फिर से चलाता हूं। गन्दा, बिलकुल भी आदर्श नहीं, हमारी निर्माण प्रक्रिया में नहीं। अभी भी एक बेहतर तरीके की तलाश में है (jUnit 4.12)।
रीबकेह

9

जब setUp()परीक्षण वर्ग (जैसे AbstractTestBaseनीचे) के सुपरक्लास में होता है, तो स्वीकृत उत्तर को निम्नानुसार संशोधित किया जा सकता है:

public abstract class AbstractTestBase {
    private static Class<? extends AbstractTestBase> testClass;
    .....
    public void setUp() {
        if (this.getClass().equals(testClass)) {
            return;
        }

        // do the setup - once per concrete test class
        .....
        testClass = this.getClass();
    }
}

यह एक एकल गैर-स्थिर setUp()पद्धति के लिए काम करना चाहिए, लेकिन मैं tearDown()जटिल प्रतिबिंब की दुनिया में भटकाए बिना एक समान उत्पादन करने में असमर्थ हूं ... बाउंटी किसी को भी इंगित कर सकता है जो कर सकता है!


3

संपादित करें: मुझे सिर्फ डिबगिंग करते समय पता चला कि क्लास को हर टेस्ट से पहले भी तुरंत किया जाता है। मुझे लगता है कि यहाँ @BeforeClass एनोटेशन सबसे अच्छा है।

तुम भी निर्माता पर सेट कर सकते हैं, परीक्षण वर्ग है सब के बाद एक वर्ग। मुझे यकीन नहीं है कि यह एक बुरा अभ्यास है क्योंकि लगभग सभी अन्य तरीकों को एनोटेट किया गया है, लेकिन यह काम करता है। आप इस तरह एक निर्माणकर्ता बना सकते हैं:

public UT () {
    // initialize once here
}
@Test
// Some test here...

परीक्षण से पहले ctor को बुलाया जाएगा क्योंकि वे स्थिर नहीं हैं।


0

इस समाधान का प्रयास करें: https://stackoverflow.com/a/46274919/907576 :

@BeforeAllMethods/ @AfterAllMethodsएनोटेशन के साथ आप उदाहरण के संदर्भ में टेस्ट क्लास में किसी भी विधि को निष्पादित कर सकते हैं, जहां सभी इंजेक्शन मूल्य उपलब्ध हैं।


तीसरे पक्ष के पुस्तकालय पर निर्भर करता है।
एंड्रयू

0

मेरा गंदा समाधान है:

public class TestCaseExtended extends TestCase {

    private boolean isInitialized = false;
    private int serId;

    @Override
    public void setUp() throws Exception {
        super.setUp();
        if(!isInitialized) {
            loadSaveNewSerId();
            emptyTestResultsDirectory();
            isInitialized = true;
        }
    }

   ...

}

मैं इसे अपने सभी टेस्टकेस में बेस बेस के रूप में उपयोग करता हूं।


सार्वजनिक वर्ग TestCaseExtended का विस्तार TestCase {निजी स्टैटिक बूलियन isInitialized = false; निजी स्थिर TestCaseExtended caseExtended; निजी int serId; @ ओवरराइड सार्वजनिक शून्य सेटअप () थ्रेड अपवाद {सुपर.सेटअप (); if (isInitialized) {caseExtended = new TestCaseExtended (); caseExtended.loadSaveNewSerId (); caseExtended.emptyTestResultsDirectory (); isInitialized = true; }}
ओबी टू

0

यदि आप एक ऐसे चर की घोषणा को बाध्य नहीं करना चाहते हैं जो प्रत्येक उप-प्रकार पर सेट और जाँच की जाती है, तो इसे एक सुपरटाइट में जोड़ा जा सकता है:

public abstract class SuperTest {

    private static final ConcurrentHashMap<Class, Boolean> INITIALIZED = new ConcurrentHashMap<>();
    protected final boolean initialized() {
        final boolean[] absent = {false};
        INITIALIZED.computeIfAbsent(this.getClass(), (klass)-> {
            return absent[0] = true;
        });
        return !absent[0];
    }
}



public class SubTest extends SuperTest {
    @Before
    public void before() {
        if ( super.initialized() ) return;

         ... magic ... 
    }

}

0

मैंने इस समस्या को इस तरह हल किया:

अपने आधार सार वर्ग में जोड़ें (मेरा मतलब है सार वर्ग जहां आप अपने ड्राइवर को सेटअप में आरंभ करते हैं ) कोड के इस भाग में:

private static boolean started = false;
static{
    if (!started) {
        started = true;
        try {
            setUpDriver();  //method where you initialize your driver
        } catch (MalformedURLException e) {
        }
    }
}

और अब, यदि आपकी टेस्ट कक्षाएं बेस एब्स्ट्रैक्ट क्लास -> setUpDriver () पद्धति से चलेंगी, तो पहले @Test प्रति रन केवल एक बार पहले निष्पादित किया जाएगा ।


0

सभी इनिशियलाइज़ेशन कार्य करने के लिए स्प्रिंग के @PostConstruct मेथड का उपयोग करें और यह विधि किसी भी @ निष्पादित होने से पहले चलती है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.