2010-01-07 21 views
25

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

UPDATE objects SET locked = 1 WHERE id = 1234 AND locked = 0 

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

UPDATE objects SET results = '...' WHERE id = 1234 AND version = 1 

हैं, तो अपने संस्करण से मेल नहीं होगा और इसलिए परिणाम छोड़ दिए जाएंगे।

इन दो परमाणु अद्यतनों को किसी भी संभावित दौड़ की स्थिति को संभालना चाहिए। सवाल यह है कि यूनिट परीक्षणों में इसे कैसे सत्यापित किया जाए।

पहला सेमफोर परीक्षण करना आसान है, क्योंकि यह केवल दो संभावित परिदृश्यों के साथ दो अलग-अलग परीक्षण स्थापित करने का मामला है: (1) जहां ऑब्जेक्ट लॉक है और (2) जहां ऑब्जेक्ट लॉक नहीं है। (हमें SQL क्वेरी की परमाणुता की जांच करने की आवश्यकता नहीं है क्योंकि यह डेटाबेस विक्रेता की ज़िम्मेदारी होनी चाहिए।)

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

उत्तर

26

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

मान लीजिए कि हमारे डेटाबेस में एक पंक्ति सम्मिलित कुछ कोड है:

class TestSubject 

    def insert_unless_exists 
    if !row_exists? 
     insert_row 
    end 
    end 

end 

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

class TestSubject 

    def insert_unless_exists 
    if !row_exists? 
     before_insert_row_hook 
     insert_row 
    end 
    end 

    def before_insert_row_hook 
    end 

end 

जब जंगली में चलाने के लिए, हुक CPU समय का एक छोटा सा खा को छोड़कर कुछ नहीं करता है। लेकिन जब कोड रेस स्थिति के लिए परीक्षण किया जा रहा है, परीक्षण बंदर-पैच before_insert_row_hook:

class TestSubject 
    def before_insert_row_hook 
    insert_row 
    end 
end 

कि धूर्त नहीं है? एक परजीवी वेश्या लार्वा की तरह, जिसने एक असुरक्षित कैटरपिलर के शरीर को अपहृत कर दिया है, परीक्षण ने परीक्षण के तहत कोड को अपहृत कर दिया ताकि वह सटीक स्थिति पैदा करे जिसकी हमें जांच की आवश्यकता है।

यह विचार एक्सओआर कर्सर जितना आसान है, इसलिए मुझे संदेह है कि कई प्रोग्रामर ने स्वतंत्र रूप से इसका आविष्कार किया है। मैंने दौड़ की स्थिति के साथ कोड परीक्षण के लिए आम तौर पर उपयोगी पाया है। मुझे उम्मीद है यह मदद करेगा।

+1

ए-हा। वह ऐसा करेगा।यद्यपि एक स्पष्ट हुक जोड़ने के बजाय, मैं किसी विधि की कार्यक्षमता को बढ़ाने के लिए 'alias_method_chain' का उपयोग कर सकता हूं जो कि दो सेमफोरों के बीच _has_ को बुलाया जा सकता है-लंबे समय तक चलने वाला कार्य। – Ian

+0

इयान, यह ऐसा करेगा। –

+4

+1 अपने अनुकरण में परजीवी wasp लार्वा का उपयोग करने के लिए। – aronchick

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