2008-08-27 17 views
124

मैंने सुना है कि इकाई परीक्षण "पूरी तरह से कमाल", "वास्तव में अच्छा" और "अच्छी तरह से अच्छी चीजें" है लेकिन 70% या अधिक फ़ाइलों में डेटाबेस पहुंच शामिल है (कुछ पढ़ें और कुछ लिखें) और मुझे यकीन नहीं है कि इन फ़ाइलों के लिए यूनिट परीक्षण कैसे लिखना है।डेटाबेस क्वेरीज के साथ किसी ऑब्जेक्ट का परीक्षण कैसे करें

मैं PHP और पायथन का उपयोग कर रहा हूं लेकिन मुझे लगता है कि यह एक प्रश्न है जो डेटाबेस एक्सेस का उपयोग करने वाली अधिकांश/सभी भाषाओं पर लागू होता है।

उत्तर

68

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

मजाक के लिए अपनी वस्तुओं को सेट करने के लिए, तो आप शायद नियंत्रण/निर्भरता इंजेक्शन पैटर्न के उलट किसी प्रकार का उपयोग करने के लिए, निम्नलिखित छद्म कोड में के रूप में की जरूरत है:

class Bar 
{ 
    private FooDataProvider _dataProvider; 

    public instantiate(FooDataProvider dataProvider) { 
     _dataProvider = dataProvider; 
    } 

    public getAllFoos() { 
     // instead of calling Foo.GetAll() here, we are introducing an extra layer of abstraction 
     return _dataProvider.GetAllFoos(); 
    } 
} 

class FooDataProvider 
{ 
    public Foo[] GetAllFoos() { 
     return Foo.GetAll(); 
    } 
} 
अब आप अपने इकाई परीक्षण में

, आप FooDataProvider का एक मॉक बनाते हैं, जो आपको वास्तव में डेटाबेस को हिट किए बिना GetAllFoos विधि को कॉल करने की अनुमति देता है।

class BarTests 
{ 
    public TestGetAllFoos() { 
     // here we set up our mock FooDataProvider 
     mockRepository = MockingFramework.new() 
     mockFooDataProvider = mockRepository.CreateMockOfType(FooDataProvider); 

     // create a new array of Foo objects 
     testFooArray = new Foo[] {Foo.new(), Foo.new(), Foo.new()} 

     // the next statement will cause testFooArray to be returned every time we call FooDAtaProvider.GetAllFoos, 
     // instead of calling to the database and returning whatever is in there 
     // ExpectCallTo and Returns are methods provided by our imaginary mocking framework 
     ExpectCallTo(mockFooDataProvider.GetAllFoos).Returns(testFooArray) 

     // now begins our actual unit test 
     testBar = new Bar(mockFooDataProvider) 
     baz = testBar.GetAllFoos() 

     // baz should now equal the testFooArray object we created earlier 
     Assert.AreEqual(3, baz.length) 
    } 
} 

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

+0

मुझे पता है कि यह पुराना है लेकिन डीबी में पहले से एक डुप्लिकेट टेबल बनाने के बारे में क्या है। इस तरह आप डीबी कॉल काम की पुष्टि कर सकते हैं? – bretterer

+1

मैं PHP के पीडीओ का उपयोग डेटाबेस के लिए सबसे कम स्तर तक पहुंच के रूप में कर रहा हूं, जिस पर मैंने एक इंटरफ़ेस निकाला था। फिर मैंने इसके ऊपर एक अनुप्रयोग जागरूक डेटाबेस परत बनाया। यह वह परत है जिसमें सभी कच्चे एसक्यूएल प्रश्न और अन्य जानकारी होती है। शेष एप्लिकेशन इस उच्च-स्तरीय डेटाबेस के साथ इंटरैक्ट करता है। मुझे यह इकाई परीक्षण के लिए बहुत अच्छी तरह से काम करने के लिए मिला है; मैं अपने एप्लिकेशन पेजों का परीक्षण करता हूं कि वे एप्लिकेशन डेटाबेस के साथ कैसे बातचीत करते हैं। मैं अपने एप्लिकेशन डेटाबेस का परीक्षण करता हूं कि यह पीडीओ के साथ कैसे इंटरैक्ट करता है। मुझे लगता है कि पीडीओ बिना बग के काम करता है। स्रोत कोड: http://manx.codeplex.com – legalize

+0

@bretterer - एक डुप्लिकेट तालिका बनाना एकीकरण परीक्षण के लिए अच्छा है। यूनिट परीक्षण के लिए आप आम तौर पर एक मॉक ऑब्जेक्ट का उपयोग करेंगे जो आपको डेटाबेस की परवाह किए बिना कोड की इकाई का परीक्षण करने की अनुमति देगा। – BornToCode

23

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

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

मेरी सी # परियोजनाओं में, मैं पूरी तरह अलग डेटा परत के साथ एनएचबेर्नेट का उपयोग करता हूं। मेरी वस्तुएं कोर डोमेन मॉडल में रहती हैं और मेरी एप्लिकेशन परत से एक्सेस की जाती हैं। एप्लिकेशन परत डेटा परत और डोमेन मॉडल परत दोनों से बात करती है।

एप्लिकेशन परत को कभी-कभी "बिजनेस लेयर" भी कहा जाता है।

यदि आप PHP का उपयोग कर रहे हैं, तो केवल डेटा पहुंच के लिए कक्षाओं का एक विशिष्ट सेट बनाएं। सुनिश्चित करें कि आपकी ऑब्जेक्ट्स को पता नहीं है कि वे कैसे बने रहते हैं और आपके आवेदन कक्षाओं में से दो को तार देते हैं।

एक और विकल्प मॉकिंग/स्टब्स का उपयोग करना होगा।

+0

मैं हमेशा इस पर सहमत हूं लेकिन समय सीमा के कारण अभ्यास में हूं और "ठीक है, अब आज दोपहर 2 बजे तक एक और सुविधा जोड़ें" यह हासिल करने वाली सबसे कठिन चीजों में से एक है। इस तरह की चीज रिफैक्टरिंग का एक प्रमुख लक्ष्य है, हालांकि, अगर मेरे मालिक ने कभी फैसला किया है कि उसने 50 नई उभरती समस्याओं के बारे में सोचा नहीं है जिसके लिए सभी नए व्यापार तर्क और तालिकाओं की आवश्यकता है। –

+1

यदि आपकी ऑब्जेक्ट्स आपकी डेटा परत से कसकर मिलती हैं, तो उचित इकाई परीक्षण करना मुश्किल है। यूनिट परीक्षण का पहला भाग "इकाई" है। सभी इकाइयों को अलगाव में परीक्षण करने में सक्षम होना चाहिए। अच्छी व्याख्या –

6

यदि आप अपनी कक्षाओं का परीक्षण करना चाहते हैं तो आपको डेटाबेस एक्सेस का नकल करना चाहिए। आखिरकार, आप एक यूनिट टेस्ट में डेटाबेस का परीक्षण नहीं करना चाहते हैं। यह एकीकरण परीक्षण होगा।

कॉल को दूर करें और फिर एक नकली डालें जो केवल अपेक्षित डेटा लौटाता है। यदि आपकी कक्षाएं क्वेरी निष्पादित करने से अधिक नहीं करती हैं, तो शायद उन्हें परीक्षण करने योग्य भी नहीं हो सकता है, हालांकि ...

2

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

जब तक मैं डेटा एक्सेस भाग का मज़ाक उड़ाता हूं तब तक मैं यूनिट परीक्षण लिखने से निराश होता था इसलिए मुझे परीक्षण डीबी बनाने या फ्लाई पर परीक्षण डेटा उत्पन्न करने की आवश्यकता नहीं थी। डेटा का मज़ाक उड़ाकर आप इसे रन टाइम पर उत्पन्न कर सकते हैं और सुनिश्चित कर सकते हैं कि आपकी ऑब्जेक्ट ज्ञात इनपुट के साथ ठीक से काम करती है।

2

आप डेटाबेस इंजन को सारणीबद्ध करने के लिए मॉकिंग फ्रेमवर्क का उपयोग कर सकते हैं। मुझे नहीं पता कि PHP/पायथन को कुछ मिला है लेकिन टाइप की गई भाषाओं (सी #, जावा इत्यादि) के लिए बहुत सारे विकल्प हैं

यह भी निर्भर करता है कि आपने उन डेटाबेस एक्सेस कोड को कैसे डिज़ाइन किया है, क्योंकि कुछ डिज़ाइन यूनिट के लिए आसान हैं पिछले पदों की तरह अन्य की तुलना में परीक्षण का उल्लेख किया गया है।

2

मैंने इसे PHP में कभी नहीं किया है और मैंने कभी भी पायथन का उपयोग नहीं किया है, लेकिन आप जो करना चाहते हैं वह डेटाबेस को कॉल का मज़ाक उड़ाता है। ऐसा करने के लिए आप कुछ IoC लागू कर सकते हैं चाहे तृतीय पक्ष टूल या आप इसे स्वयं प्रबंधित करते हैं, तो आप डेटाबेस कॉलर के कुछ नकली संस्करण को कार्यान्वित कर सकते हैं, जहां आप उस नकली कॉल के परिणाम को नियंत्रित करेंगे।

आईओसी का एक साधारण रूप इंटरफ़ेस को कोडिंग करके किया जा सकता है। इसके लिए आपके कोड में कुछ प्रकार के ऑब्जेक्ट ओरिएंटेशन की आवश्यकता होती है, इसलिए यह आपके काम पर लागू नहीं हो सकता है (मैं कहता हूं कि चूंकि मुझे केवल PHP और पायथन का उल्लेख है)

आशा है कि यह उपयोगी है, अगर कुछ भी नहीं है अन्यथा आपको अभी खोजने के लिए कुछ शर्तें मिल गई हैं।

2

मैं पहली पोस्ट के साथ सहमत हूं - डेटाबेस एक्सेस को एक डीएओ परत में हटा दिया जाना चाहिए जो एक इंटरफ़ेस लागू करता है। फिर, आप डीएओ परत के स्टब कार्यान्वयन के खिलाफ अपने तर्क का परीक्षण कर सकते हैं।

4

पुस्तक xUnit Test Patterns एक डेटाबेस को हिट करने वाले यूनिट-परीक्षण कोड को संभालने के कुछ तरीकों का वर्णन करती है। मैं उन अन्य लोगों से सहमत हूं जो कह रहे हैं कि आप ऐसा नहीं करना चाहते हैं क्योंकि यह धीमा है, लेकिन आपको इसे कभी-कभी करना होगा, आईएमओ। उच्च स्तरीय सामान का परीक्षण करने के लिए डीबी कनेक्शन का मजाक करना एक अच्छा विचार है, लेकिन वास्तविक पुस्तक के साथ बातचीत करने के लिए आप जो चीजें कर सकते हैं, उसके बारे में सुझावों के लिए इस पुस्तक को देखें।

2

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

उदाहरण के लिए, यदि आप इकाई को अपने यूजर इंटरफेस क्लास का परीक्षण करते हैं तो आपके द्वारा लिखे गए परीक्षणों को यूआई के अंदर तर्क को सत्यापित करने की कोशिश की जानी चाहिए, न कि उस कार्य के पीछे व्यापार तर्क या डेटाबेस कार्रवाई।

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

व्यक्तिगत रूप से मेरे लिए यूनिट परीक्षण की छिपी हुई शक्ति यह है कि यह मुझे मेरे अनुप्रयोगों को उनके बिना संभवतः बेहतर तरीके से डिजाइन करने के लिए मजबूर करता है। ऐसा इसलिए है क्योंकि इससे वास्तव में मुझे "इस कार्य को सबकुछ करना चाहिए" मानसिकता से दूर तोड़ने में मदद मिली।

क्षमा करें मेरे पास PHP/पायथन के लिए कोई विशिष्ट कोड उदाहरण नहीं हैं, लेकिन यदि आप .NET उदाहरण देखना चाहते हैं तो मेरे पास post है जो एक तकनीक का वर्णन करता है जिसे मैं ऐसा ही करता था।

4

विकल्प आपके पास:

  • एक स्क्रिप्ट है कि बाहर डेटाबेस हटा दिया जाएगा इससे पहले कि आप इकाई परीक्षण शुरू लिखें, फिर डेटा के पूर्व-निर्धारित साथ db पॉप्युलेट और परीक्षण चला। आप यह भी कर सकते हैं कि प्रत्येक टेस्ट – से पहले यह धीमा हो जाएगा, लेकिन कम त्रुटि प्रवण होगी।
  • डेटाबेस इंजेक्ट करें। (छद्म-जावा में उदाहरण, लेकिन सभी ओओ-भाषाओं पर लागू होता है)

     
    class Database { 
    public Result query(String query) {... real db here ...} 
    }

    class MockDatabase extends Database { public Result query(String query) { return "mock result"; } }

    class ObjectThatUsesDB { public ObjectThatUsesDB(Database db) { this.database = db; } }

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

  • पूरे कोड में डीबी का उपयोग न करें (वैसे भी यह एक बुरा अभ्यास है)। एक "डेटाबेस" उद्देश्य यह है कि बजाय परिणामों के साथ लौटने के सामान्य वस्तुओं वापस आ जाएगी बनाएं (यानी वापस आ जाएगी एक टपल {name: "marcin", password: "blah"} के बजाय User) लिखने तदर्थ के साथ अपने सभी परीक्षण असली वस्तुओं का निर्माण किया और एक बड़ा परीक्षण है कि एक डेटाबेस पर निर्भर करता है लिखते हैं कि सुनिश्चित करता है कि यह रूपांतरण ठीक काम करता है।

बेशक ये दृष्टिकोण पारस्परिक रूप से अनन्य नहीं हैं और आप उन्हें मिश्रण और मिलान कर सकते हैं।

11

डेटाबेस एक्सेस के साथ किसी ऑब्जेक्ट का परीक्षण करने का सबसे आसान तरीका लेनदेन स्कॉप्स का उपयोग कर रहा है।

उदाहरण के लिए:

[Test] 
    [ExpectedException(typeof(NotFoundException))] 
    public void DeleteAttendee() { 

     using(TransactionScope scope = new TransactionScope()) { 
      Attendee anAttendee = Attendee.Get(3); 
      anAttendee.Delete(); 
      anAttendee.Save(); 

      //Try reloading. Instance should have been deleted. 
      Attendee deletedAttendee = Attendee.Get(3); 
     } 
    } 

यह डेटाबेस के राज्य वापस लौट जाएगा मूल रूप से एक लेन-देन रोलबैक की तरह ताकि आप के रूप में आप किसी भी sideeffects बिना चाहते हैं परीक्षण के रूप में कई बार चला सकते हैं। हमने बड़ी परियोजनाओं में सफलतापूर्वक इस दृष्टिकोण का उपयोग किया है। हमारे निर्माण को चलाने में थोड़ा लंबा समय लगता है (15 मिनट), लेकिन 1800 यूनिट परीक्षण होने के लिए यह भयानक नहीं है। साथ ही, यदि निर्माण का समय चिंता का विषय है, तो आप बिल्डिंग प्रक्रिया को कई बिल्ड करने के लिए बदल सकते हैं, एक बनाने के लिए, एक अन्य जो बाद में आग लगता है जो इकाई परीक्षण, कोड विश्लेषण, पैकेजिंग इत्यादि को संभालता है ...

+0

+1 यूनिट परीक्षण डेटा एक्सेस परतों पर बहुत समय बचाता है। बस ध्यान दें कि टीएस को अक्सर एमएसडीटीसी की आवश्यकता होगी जो शायद वांछनीय नहीं हो सकता है (इस पर निर्भर करता है कि आपके ऐप को एमएसडीटीसी की आवश्यकता होगी) – StuartLC

+0

मूल प्रश्न PHP के बारे में था, यह उदाहरण सी # प्रतीत होता है। वातावरण बहुत अलग हैं। – legalize

+1

प्रश्न के लेखक ने कहा कि यह एक सामान्य प्रश्न है जो सभी भाषाओं को लागू करता है जिनके पास डीबी के साथ कुछ करना है। – Vedran

6

मैं शायद आपको हमारे अनुभव का स्वाद दे सकता हूं जब हमने यूनिट-स्तरीय प्रक्रिया को यूनिट परीक्षण करना शुरू किया जिसमें "व्यापार तर्क" एसक्यूएल संचालन का एक टन शामिल था।

हमने पहली बार एक अमूर्त परत बनाई जिसने हमें किसी भी उचित डेटाबेस कनेक्शन में "स्लॉट" करने की अनुमति दी (हमारे मामले में, हमने बस एक ओडीबीसी-प्रकार कनेक्शन का समर्थन किया)।

एक बार इस स्थान पर था, हम तो हमारे कोड में कुछ इस तरह करने में सक्षम थे (हम सी ++ में काम करते हैं, लेकिन मुझे यकीन है कि आप विचार प्राप्त कर रहा हूँ):।

GetDatabase() ExecuteSQL (" INSERT INTO foo (blah, blah) ")

सामान्य रन समय पर, GetDatabase() एक ऑब्जेक्ट वापस करेगा जो हमारे सभी एसक्यूएल (क्वेरी सहित) को ओडीबीसी के माध्यम से सीधे डेटाबेस में खिलाएगा।

फिर हमने इन-मेमोरी डेटाबेस को देखना शुरू कर दिया - लंबे समय तक सबसे अच्छा SQLite लगता है। (http://www.sqlite.org/index.html)। यह सेट अप करने और उपयोग करने के लिए उल्लेखनीय रूप से सरल है, और हमें subclass और GetDatabase() को एसक्यूएल को एक इन-मेमोरी डेटाबेस में अग्रेषित करने की अनुमति देता है जो प्रत्येक परीक्षण के लिए बनाया और नष्ट किया गया था।

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

कुल मिलाकर, इसने हमारी टीडीडी प्रक्रिया के साथ काफी मदद की है, क्योंकि कुछ बग को ठीक करने के लिए काफी निर्दोष परिवर्तनों की तरह लग रहा है, जो आपके सिस्टम के अन्य (मुश्किलों का पता लगाने) क्षेत्रों पर काफी अजीब प्रभाव डाल सकता है - बहुत प्रकृति के कारण एसक्यूएल/डेटाबेस।

जाहिर है, हमारे अनुभव एक सी ++ विकास पर्यावरण के आसपास केंद्रित हैं, हालांकि मुझे यकीन है कि आप शायद PHP/पायथन के तहत कुछ ऐसा ही काम कर सकते हैं।

उम्मीद है कि इससे मदद मिलती है।

2

इकाई परीक्षणों के लिए परीक्षण डेटा सेट करना एक चुनौती हो सकती है।

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

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