यहाँ मेरा दृष्टिकोण। यह समय के संदर्भ में लागत है क्योंकि यह 4 चरणों में एक रिफलेक्टर-परीक्षण है।
मैं इस सवाल के उदाहरण में उजागर की तुलना में अधिक जटिलता के साथ घटकों में बेहतर सूट कर सकता हूं।
वैसे भी रणनीति किसी भी घटक उम्मीदवार के लिए एक इंटरफ़ेस (DAO, सेवाएँ, नियंत्रकों, ...) द्वारा सामान्यीकृत की जाती है।
1. इंटरफ़ेस
सभी सार्वजनिक विधियों को MyDocumentService से इकट्ठा करते हैं और उन सभी को एक इंटरफ़ेस में डालते हैं। उदाहरण के लिए। यदि यह पहले से मौजूद है, तो किसी नए को सेट करने के बजाय उस का उपयोग करें ।
public interface DocumentService {
List<Document> getAllDocuments();
//more methods here...
}
फिर हम इस नए इंटरफ़ेस को लागू करने के लिए MyDocumentService को बाध्य करते हैं ।
अब तक सब ठीक है। कोई बड़ा बदलाव नहीं किया गया था, हमने वर्तमान अनुबंध का सम्मान किया और व्यवहार अछूता नहीं रहा।
public class MyDocumentService implements DocumentService {
@Override
public List<Document> getAllDocuments(){
//legacy code here as it is.
// with no changes ...
}
}
2. विरासत कोड की इकाई परीक्षण
यहां हमें कड़ी मेहनत करनी है। एक परीक्षण सूट स्थापित करने के लिए। हमें यथासंभव अधिक से अधिक मामले सेट करने चाहिए: सफल मामले और त्रुटि के मामले भी। ये अंतिम परिणाम की गुणवत्ता की भलाई के लिए हैं।
अब, MyDocumentService का परीक्षण करने के बजाय हम परीक्षण किए जाने वाले अनुबंध के रूप में इंटरफ़ेस का उपयोग करने जा रहे हैं।
Im विवरण में नहीं जा रहा हूं, इसलिए मुझे क्षमा करें यदि मेरा कोड बहुत सरल या बहुत अज्ञेय लगता है
public class DocumentServiceTestSuite {
@Mock
MyDependencyA mockDepA;
@Mock
MyDependencyB mockDepB;
//... More mocks
DocumentService service;
@Before
public void initService(){
service = MyDocumentService(mockDepA, mockDepB);
//this is purposed way to inject
//dependencies. Replace it with one you like more.
}
@Test
public void getAllDocumentsOK(){
// here I mock depA and depB
// wanted behaivors...
List<Document> result = service.getAllDocuments();
Assert.assertX(result);
Assert.assertY(result);
//... As many you think appropiate
}
}
यह चरण इस दृष्टिकोण में किसी भी अन्य की तुलना में अधिक समय लेता है। और यह सबसे महत्वपूर्ण है क्योंकि यह भविष्य की तुलनाओं के लिए संदर्भ बिंदु निर्धारित करेगा।
नोट: कोई बड़ा बदलाव नहीं किया गया और व्यवहारकर्ता अछूता नहीं रहा। मैं यहाँ SCM में एक टैग करने का सुझाव देता हूँ। टैग या शाखा कोई फर्क नहीं पड़ता। बस एक संस्करण है।
हम इसे रोलबैक, संस्करणों की तुलना के लिए चाहते हैं और पुराने कोड और नए के समानांतर निष्पादन के लिए हो सकते हैं।
3. परावर्तन
रिफ्लेक्टर एक नए घटक में लागू होने जा रहा है। हम मौजूदा कोड पर कोई बदलाव नहीं करेंगे। पहला कदम MyDocumentService की कॉपी और पेस्ट करना जितना आसान है और इसे CustomDocumentService (उदाहरण के लिए) का नाम बदलें ।
नई कक्षा DocumentService को लागू करती रहती है । तब जाओ और getAllDocuments () को फिर से सक्रिय करें । (एक से शुरू करें। पिन-रिफ्लेक्टर)
इसे DAO के इंटरफ़ेस / विधियों पर कुछ बदलावों की आवश्यकता हो सकती है। यदि हां, तो मौजूदा कोड को न बदलें। DAO इंटरफ़ेस में अपनी खुद की विधि को लागू करें। पुराने कोड को डिप्रेस्ड के रूप में एनोटेट करें और आपको बाद में पता चल जाएगा कि क्या हटाया जाना चाहिए।
मौजूदा कार्यान्वयन को तोड़ना / बदलना महत्वपूर्ण नहीं है। हम समानांतर में दोनों सेवाओं को निष्पादित करना चाहते हैं और फिर परिणामों की तुलना करते हैं।
public class CustomDocumentService implements DocumentService {
@Override
public List<Document> getAllDocuments(){
//new code here ...
//due to im refactoring service
//I do the less changes possible on its dependencies (DAO).
//these changes will come later
//and they will have their own tests
}
}
4. अद्यतन कर रहा है DocumentServiceTestSuite
ठीक है, अब आसान हिस्सा है। नए घटक के परीक्षणों को जोड़ने के लिए।
public class DocumentServiceTestSuite {
@Mock
MyDependencyA mockDepA;
@Mock
MyDependencyB mockDepB;
DocumentService service;
DocumentService customService;
@Before
public void initService(){
service = MyDocumentService(mockDepA, mockDepB);
customService = CustomDocumentService(mockDepA, mockDepB);
// this is purposed way to inject
//dependencies. Replace it with the one you like more
}
@Test
public void getAllDocumentsOK(){
// here I mock depA and depB
// wanted behaivors...
List<Document> oldResult = service.getAllDocuments();
Assert.assertX(oldResult);
Assert.assertY(oldResult);
//... As many you think appropiate
List<Document> newResult = customService.getAllDocuments();
Assert.assertX(newResult);
Assert.assertY(newResult);
//... The very same made to oldResult
//this is optional
Assert.assertEquals(oldResult,newResult);
}
}
अब हमारे पास पुराने। और newResult दोनों स्वतंत्र रूप से मान्य हैं लेकिन हम एक दूसरे से तुलना भी कर सकते हैं। यह अंतिम सत्यापन वैकल्पिक है और यह परिणाम पर निर्भर है। यह तुलनीय नहीं हो सकता है।
इस तरह से दो संग्रहों की तुलना करने के लिए बहुत अधिक सघन नहीं हो सकता है, लेकिन किसी भी अन्य प्रकार की वस्तु (pojos, डेटा मॉडल एंटिटीज़, DTO, रैपर्स, देशी प्रकार ...) के लिए मान्य होगा।
टिप्पणियाँ
मैं यह बताने की हिम्मत नहीं करूंगा कि यूनिट परीक्षण कैसे करें या नकली कामों का उपयोग कैसे करें। मुझे यह कहने की हिम्मत नहीं हुई कि आपको रिफ्लेक्टर कैसे करना है। मैं एक वैश्विक रणनीति का सुझाव देना चाहता था। इसे कैसे आगे बढ़ाया जाए यह आप पर निर्भर करता है। आपको पता है कि कोड कैसा है, इसकी जटिलता और अगर इस तरह की रणनीति एक कोशिश के लायक है। समय और संसाधन जैसे तथ्य यहां मायने रखते हैं। यह भी मायने रखता है कि आप भविष्य में इन परीक्षणों से क्या उम्मीद करते हैं।
मैंने अपने उदाहरण एक सेवा द्वारा शुरू किए हैं और मैं डीएओ और इतने पर पालन करूंगा। निर्भरता के स्तर में गहराई तक जा रहे हैं। कमोबेश इसे ऊपर-नीचे की रणनीति के रूप में वर्णित किया जा सकता है । हालांकि मामूली बदलाव / रिफ्लेक्टर ( जैसे कि दौरे के उदाहरण में उजागर ), एक नीचे की ओर काम आसान होगा। क्योंकि बदलावों की गुंजाइश बहुत कम है।
अंत में, यह आप पर निर्भर है कि हटाए गए कोड को हटा दें और पुराने आश्रितों को नए पर पुनर्निर्देशित करें।
हटाए गए परीक्षणों और नौकरी को भी हटा दिया जाता है। यदि आपने इसके परीक्षणों के साथ पुराने समाधान का संस्करण दिया है, तो आप किसी भी समय एक दूसरे की जांच और तुलना कर सकते हैं।
इतने काम के परिणाम में, आपके पास विरासत कोड का परीक्षण, सत्यापन और संस्करण है। और नया कोड, परीक्षण, मान्य और संस्करण के लिए तैयार है।