2011-02-11 13 views
17

मुझे यहां कुछ याद आना चाहिए। ActivityUnitTestCase की JavaDoc का सुझाव है कि इस परीक्षण का मामला प्रणाली से अलगाव में एक गतिविधि का परीक्षण करती है:ActivityUnitTestCase को एप्लिकेशन.ऑनक्रेट कॉल करने से कैसे रोकें?

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

मुझे लगता है कि वास्तव में एप्लिकेशन शुरू नहीं करना शामिल है। इसके अलावा, यह setApplication सहायक का खुलासा करता है जिसे कोई संभावित रूप से नकली एप्लिकेशन इंजेक्ट करने के लिए उपयोग कर सकता है।

हालांकि, कोई भी ActivityUnitTestCase मैंने (वास्तविक) एप्लिकेशन लॉन्च करना शुरू किया और onCreate विधि को कॉल किया। अधिक सटीक रूप से, InstrumentationTestRunner ऐसा करने लगता है, और मुझे अपने परीक्षण के setUp विधि में setApplication का मौका मिलने से पहले ऐसा करना! मैंने यह भी ध्यान नहीं दिया कि थोड़ी देर के लिए, ऐसा लगता है कि यह टेस्ट सूट लॉन्च के दौरान एक बिंदु पर होता है, जहां ग्रहण ब्रेकपॉइंट्स भी नहीं पहुंचते हैं, लेकिन onCreate में लॉग पर लिखने से पता चलता है कि इसे वास्तव में बुलाया जाता है।

यह पूरी तरह से मेरे बाहर है। मैं एक मॉक ऐप ऑब्जेक्ट का उपयोग क्यों करना चाहूंगा जब एंड्रॉइड के टेस्ट रनर वैसे भी वास्तविक एप्लिकेशन को तुरंत चालू और निष्पादित करते हैं? यह और भी समस्याग्रस्त है क्योंकि उपकरण धावक अपने धागे में चलता है, और ऐसा करते समय मुख्य अनुप्रयोग धागे को जन्म देता है। इसका मतलब है कि परीक्षण निष्पादित होने और Application.onCreate के बीच दौड़ की स्थिति है। यदि आप वहां कुछ भी करते हैं जो आपके परीक्षणों को प्रभावित कर सकता है, उदा। एक साझा वरीयता फ़ाइल को लिखना, फिर आप पूरी तरह से खराब हो गए हैं, क्योंकि आपके परीक्षण यादृच्छिक रूप से असफल हो जाएंगे।

क्या मुझे कुछ याद आ रहा है या यह परीक्षण ढांचे में बस एक सकल निरीक्षण है?

अद्यतन यह ApplicationTestCase को भी प्रभावित करता है। मेरे टेस्ट केस शुरू होने से पहले, मैं अपने आवेदन वर्ग 'onCreate में ब्रेकपॉइंट तक पहुंच सकता हूं। हम वहां एक अग्निशमन और एसिंक टास्क शुरू करते हैं, जो यादृच्छिक रूप से विफल हो जाएगा क्योंकि मुझे इसे मजाक करने का कोई मौका नहीं मिलता है (याद रखें, setUp से पहले मेरे टेस्ट केस पर कॉल किया गया है)। यहाँ स्टैक ट्रेस मैं onCreate के इस अस्पष्ट मंगलाचरण के दौरान नज़र है:

Thread [<1> main] (Suspended (breakpoint at line 86 in QypeRadar)) 
QypeRadar.onCreate() line: 86 
InstrumentationTestRunner(Instrumentation).callApplicationOnCreate(Application) line: 969 
ActivityThread.handleBindApplication(ActivityThread$AppBindData) line: 4244 
ActivityThread.access$3000(ActivityThread, ActivityThread$AppBindData) line: 125  
ActivityThread$H.handleMessage(Message) line: 2071 
ActivityThread$H(Handler).dispatchMessage(Message) line: 99 
Looper.loop() line: 123 
ActivityThread.main(String[]) line: 4627  
Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method] 
Method.invoke(Object, Object...) line: 521 
ZygoteInit$MethodAndArgsCaller.run() line: 868 
ZygoteInit.main(String[]) line: 626 
NativeStart.main(String[]) line: not available [native method] 

क्यों परीक्षण धावक callApplicationOnCreate भी the docs हालांकि स्पष्ट रूप से राज्य:

परीक्षण का मामला OnCreate() जब तक फोन नहीं होगा अपने परीक्षण कॉल बनाएँ आवेदन()। यह आपको क्रिएट() से पहले किसी भी अतिरिक्त ढांचे या परीक्षण तर्क को स्थापित या समायोजित करने का मौका देता है।

यह एक सपाट झूठ है - यह मुझे मौका नहीं देता है!

+0

जहां तक ​​मैं कह सकता हूं, इसे ठीक करने के केवल दो तरीके हैं: 1) इंस्ट्रुमेंटेशन टेस्टरुनर को कॉल करने के लिए कॉल करें 'कॉल एप्प्लिकेशनऑनक्रेट' पर कॉल न करें और यह तय करने के लिए परीक्षण केस पर छोड़ दें कि वह चाहता है या नहीं। सुनिश्चित नहीं है कि अन्य परीक्षणों पर इसका क्या प्रभाव होगा। 2) साइड इफेक्ट मुक्त और बेवकूफ होने के लिए हमारी ऑनक्रेट विधि को दोबारा लिखें (याद रखें कि इसे दो बार बुलाया जाएगा, क्योंकि टेस्ट केस काम करने के लिए आपको 'createAplication' भी कॉल करना होगा)। विचार? – Matthias

+0

इसलिए, मैंने एक कस्टम टेस्ट रनर बनाया है जो 'कॉल एप्प्लिकेशनऑनक्रेट' को छोड़ देता है, अब सब कुछ * यूनिट * परीक्षणों के लिए अपेक्षित काम करता है। कार्यात्मक परीक्षणों के लिए, मुझे अभी भी एक पूर्ण परीक्षण धावक की आवश्यकता होगी जो पूर्ण लॉन्च करता है, इसलिए अब मेरे पास दो टेस्ट धावक हैं, जो दर्द का एक सा है। – Matthias

+0

दिलचस्प लेखन-अप। क्या यह केवल उचित परीक्षण केस प्रकारों के लिए 'callAplicationOnCreate' को बाईपास करने के लिए पर्याप्त होगा, जिससे आप परीक्षण धावक के लिए पैच बनाने की अनुमति दे सकते हैं जिसे आप अपस्ट्रीम भेज सकते हैं? –

उत्तर

3

Roboguice एक ही समस्या थी। इसे here देखें।

+3

+1, मुझे पहले 'attachBaseContext' के बारे में पता नहीं था! हालांकि, यह मदद नहीं करता है: परीक्षण धावक अभी भी नो-तर्क कन्स्ट्रक्टर का आह्वान करता है, और यदि मैं इसे हटा देता हूं, तो मुझे अपवाद मिलता है: "InstantiationException - newInstance विफल: ()"। अगर मैं नो-Args ctor को छोड़ देता हूं, तो ऑनक्रेट को अभी भी मूल ऐप ऑब्जेक्ट पर कॉल किया जा रहा है, भले ही मैं सेट एप्लिकेशंस को कॉल करता हूं या नहीं, इसलिए समस्या बनी हुई है। – Matthias

+0

जबकि यह सैद्धांतिक रूप से प्रश्न का उत्तर दे सकता है, [यह बेहतर होगा] (// meta.stackoverflow.com/q/8259) यहां उत्तर के आवश्यक हिस्सों को शामिल करने के लिए, और संदर्भ के लिए लिंक प्रदान करें। – nhaarman

2

मैं डैगर के साथ परीक्षण कर रहा हूं, इसलिए शायद यह आपका मामला भी है, क्योंकि आप शायद इंजेक्ट करना चाहते हैं और एप्लिकेशन में जो कुछ भी कॉल नहीं करना चाहते हैं।onCreate, तो यह एक है मुझे (api17 +) के लिए ठीक काम करता है:

private Context mContext; 
private Application mApplication; 

@Override 
protected void setUp() throws Exception { 
    super.setUp(); 

    mContext = new ContextWrapper(getInstrumentation().getTargetContext()) { 
     @Override 
     public Context getApplicationContext() { 
      return mApplication; 
     } 
    }; 
    mApplication = new MyAppMock(); 
    mApplication.attachBaseContext(mContext); 

    setApplication(app); 
} 

public void testActivityCreated() { 
    Intent intent = AboutActivity.createIntent(mContext); 
    setActivityContext(mContext); 
    startActivity(intent, null, null); 
    assertNotNull(getActivity()); 
} 

< लिए api16 आप अन्यथा यह दुर्घटना होगा, प्रतिबिंब का उपयोग करें और के बजाय Application.attach(context) फोन Application.attachBaseContext()Application.mLoadedApk स्थापित करने के लिए की जरूरत है।

मैं सब कुछ एक साथ रखा और पता चलता है कि चाकू के साथ परीक्षण करने के लिए कैसे डेमो एप्लिकेशन बना दिया है: https://github.com/vovkab/dagger-unit-test

यह भी दिखाता है कि आपके आवेदन उपहास करने के लिए, किसी भी एंड्रॉयड संस्करण के लिए काम करता है।

+0

क्या आप "डैगर-यूनिट-टेस्ट" टेस्ट क्लास का परीक्षण करने में सक्षम हैं? मैंने इस दृष्टिकोण को स्वयं करने की कोशिश की लेकिन असफल रहा क्योंकि डैगर शिकायत करता है कि टेस्ट मॉड्यूल में लक्ष्य वर्ग पंजीकृत नहीं है - यह लक्ष्य वर्ग को इंजेक्शन योग्य ऐपमोक के बजाय अनाम वर्ग MyTestClass $ 2 के रूप में देख रहा है (जो मॉड्यूल में निर्दिष्ट है "इंजेक्ट" इसकी "मॉड्यूल" एनोटेशन – twelve17

+0

इस बारे में निश्चित नहीं है कि आप किस नमूना कोड के बारे में बात कर रहे हैं, आपके द्वारा वर्णित वर्ग नाम मेल नहीं खाते हैं और न ही यह उदाहरण और न ही उदाहरण जीथब पर होस्ट किया गया है। मेरे नमूना ऐप में जिथब पर होस्ट किया गया है, मैं मुख्य गतिविधि वर्ग इंजेक्ट करता हूं: @ मॉड्यूल (इंजेक्ट्स = मेनएक्टिविटी.क्लास)। हाँ यह ठीक काम करता है, कृपया उदाहरण के लिए यहां एक नज़र डालें: https://github.com/vovkab/dagger-unit-test – vovkab

+0

क्षमा करने के लिए क्षमा न करें। मुझे स्पष्ट रूप से होना चाहिए था गलत कोड - मैं अभी उस प्रोजेक्ट पर वापस आ गया था जिस पर मैं काम कर रहा था, और मुझे जो एहसास हुआ था वह था कि मैं ['setActivityContext (mContext); '] (https://github.com/vovkab/ चाकू-यूनिट-परीक्षा/ब्लॉब/मास्टर/ऐप्स/s आरसी/एंड्रॉइडटेस्ट/जावा/वोवकाब/डैग्रेरेक्स नमूना/मुख्य एक्टिविटी यूनीटटेस्ट.जावा # एल 5 9) आपके उदाहरण से। धन्यवाद! – twelve17

संबंधित मुद्दे