2012-09-17 25 views
6

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

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

तो मेरे दृष्टिकोण से - सरल सीआरयूडी संचालन के लिए एकीकरण परीक्षण लिखना विशेष रूप से जब स्प्रिंग डेटा/हाइबरनेट जैसे ढांचे का उपयोग करना एक बड़ा प्रयास नहीं है। कभी-कभी यह भी आसान होता है, क्योंकि आप इस बारे में नहीं सोचते कि कैसे और कैसे नकल करना है।

तो मुझे अपने सीआरयूडी संचालन के लिए यूनिट टेस्ट क्यों लिखना चाहिए जो एकीकरण टेस्ट के रूप में कम विश्वसनीय हैं?

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

तो - किसी भी राय या सुझावों की अत्यधिक सराहना की जाती है! वसंत के HibernateTemplate या JdbcTemplate पर

उत्तर

10

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

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

  • सेवा इकाई परीक्षण daos नकली।
  • दाओ यूनिट परीक्षण डेटाबेस ड्राइवर (या वसंत टेम्पलेट) का नकल करते हैं या एम्बेडेड डेटाबेस (स्प्रिंग 3 में सुपर आसान) का उपयोग करते हैं।
इकाई परीक्षण करने के लिए

सेवा है कि बस दाव को होकर गुजरता है, तुम इतनी तरह नकली कर सकते हैं:

@Before 
public void setUp() { 
    service = new EventServiceImpl(); 
    dao = mock(EventDao.class); 
    service.EventDao = dao; 
} 

@Test 
public void creationDelegatesToDao() { 
    service.createEvent(sampleEvent); 
    verify(dao).createEvent(sampleEvent); 
} 

@Test(expected=EventExistsException.class) 
public void creationPropagatesExistExceptions() { 
    doThrow(new EventExistsException()).when(dao).createEvent(sampleEvent); 
    service.createEvent(sampleEvent); 
} 

@Test 
public void updatesDelegateToDao() { 
    service.updateEvent(sampleEvent); 
    verify(dao).updateEvent(sampleEvent); 
} 

@Test 
public void findingDelgatesToDao() { 
    when(dao.findEventById(7)).thenReturn(sampleEvent); 
    assertThat(service.findEventById(7), equalTo(sampleEvent)); 

    service.findEvents("Alice", 1, 5); 
    verify(dao).findEventsByName("Alice", 1, 5); 

    service.findEvents(null, 10, 50); 
    verify(dao).findAllEvents(10, 50); 
} 

@Test 
public void deletionDelegatesToDao() { 
    service.deleteEvent(sampleEvent); 
    verify(dao).deleteEvent(sampleEvent); 
} 

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

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

अब, यूनिट परीक्षण दास के लिए, मुझे एक एम्बेडेड डेटाबेस का उपयोग करना पसंद है।

private EmbeddedDatabase database; 
private EventDaoJdbcImpl eventDao = new EventDaoJdbcImpl(); 

@Before 
public void setUp() { 
    database = new EmbeddedDatabaseBuilder() 
      .setType(EmbeddedDatabaseType.H2) 
      .addScript("schema.sql") 
      .addScript("init.sql") 
      .build(); 
    eventDao.jdbcTemplate = new JdbcTemplate(database); 
} 

@Test 
public void creatingIncrementsSize() { 
    Event e = new Event(9, "Company Softball Game"); 

    int initialCount = eventDao.findNumberOfEvents(); 
    eventDao.createEvent(e); 
    assertThat(eventDao.findNumberOfEvents(), is(initialCount + 1)); 
} 

@Test 
public void deletingDecrementsSize() { 
    Event e = new Event(1, "Poker Night"); 

    int initialCount = eventDao.findNumberOfEvents(); 
    eventDao.deleteEvent(e); 
    assertThat(eventDao.findNumberOfEvents(), is(initialCount - 1)); 
} 

@Test 
public void createdEventCanBeFound() { 
    eventDao.createEvent(new Event(9, "Company Softball Game")); 
    Event e = eventDao.findEventById(9); 
    assertThat(e.getId(), is(9)); 
    assertThat(e.getName(), is("Company Softball Game")); 
} 

@Test 
public void updatesToCreatedEventCanBeRead() { 
    eventDao.createEvent(new Event(9, "Company Softball Game")); 
    Event e = eventDao.findEventById(9); 
    e.setName("Cricket Game"); 
    eventDao.updateEvent(e); 
    e = eventDao.findEventById(9); 
    assertThat(e.getId(), is(9)); 
    assertThat(e.getName(), is("Cricket Game")); 
} 

@Test(expected=EventExistsException.class) 
public void creatingDuplicateEventThrowsException() { 
    eventDao.createEvent(new Event(1, "Id1WasAlreadyUsed")); 
} 

@Test(expected=NoSuchEventException.class) 
public void updatingNonExistentEventThrowsException() { 
    eventDao.updateEvent(new Event(1000, "Unknown")); 
} 

@Test(expected=NoSuchEventException.class) 
public void deletingNonExistentEventThrowsException() { 
    eventDao.deleteEvent(new Event(1000, "Unknown")); 
} 

@Test(expected=NoSuchEventException.class) 
public void findingNonExistentEventThrowsException() { 
    eventDao.findEventById(1000); 
} 

@Test 
public void countOfInitialDataSetIsAsExpected() { 
    assertThat(eventDao.findNumberOfEvents(), is(8)); 
} 

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

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

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

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

+0

रे, आपके विस्तृत स्पष्टीकरण और उदाहरणों के बहुत सारे धन्यवाद! मुझे लगता है कि हम पहले दृष्टिकोण लेखन एकीकरण परीक्षण के लिए चिपके रहेंगे। मैं अब तक यह कहने के लिए कहूंगा कि एक वेब अनुप्रयोग की सीआरयूडी सेवाओं के लिए यूनिट परीक्षण अच्छे हैं, लेकिन वास्तव में क्या मायने रखता है एकीकरण-परीक्षण हैं। और क्यों यह टीडीडी रास्ता नहीं कर रहा है, लेकिन सेवा लागू करने से पहले यूनिट परीक्षणों के बजाय एकीकरण परीक्षण लिखें? – fischermatte

+0

यह ठीक होगा; यूनिट टेस्ट पुलिस आपके दरवाजे पर दस्तक नहीं देगी। यह सच है कि एकीकरण परीक्षण यूनिट परीक्षण _cover_ होगा।व्यक्तिगत रूप से मैं वहां यूनिट परीक्षण (रिफैक्टरिंग में विश्वास, पूर्णता की भावना, और यह सब) होने की भावना का आनंद लेता हूं लेकिन यह सिर्फ मुझे है। यदि _you_ इकाई परीक्षणों के विरोध में एकीकरण परीक्षण के माध्यम से अपना कवरेज प्राप्त करने से खुश हैं, और आपके एकीकरण परीक्षण तेजी से चल रहे डेवलपर-जेनरेट किए गए एकीकरण परीक्षण हैं, क्यूए-जेनरेट किए गए कार्यात्मक-सिस्टम-एकीकरण-स्वीकृति-उत्पादन परीक्षणों के विपरीत, फिर शांत। :) –

1

यदि आप अपनी परियोजना के बाहर अन्य घटकों के सामने परतों को उजागर करने की योजना बनाते हैं तो आपको केवल अलगाव में प्रत्येक परत का परीक्षण करने की आवश्यकता होती है। एक वेब ऐप के लिए, रिपोजिटरी परत को लागू करने का एकमात्र तरीका सेवा परत द्वारा किया जा सकता है, और सेवा परत को लागू करने का एकमात्र तरीका नियंत्रक परत द्वारा होता है। तो परीक्षण नियंत्रक परत पर शुरू और समाप्त कर सकते हैं। पृष्ठभूमि कार्यों के लिए, इन्हें सेवा परत में शामिल किया जाता है, इसलिए यहां परीक्षण करने की आवश्यकता है।

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

यह दृष्टिकोण आप दे देंगे:

  • अच्छा कवरेज
  • realistics
  • प्रयास refectoring

हालांकि, अलगाव में परतों परीक्षण की न्यूनतम राशि के प्रयास के

  • न्यूनतम राशि का परीक्षण करती है आपकी टीम को अधिक समवर्ती रूप से काम करने की अनुमति देता है, इसलिए एक देव भंडार कर सकता है और दूसरा सेवा कर सकता है कार्यक्षमता का एक टुकड़ा, और स्वतंत्र रूप से परीक्षण किए गए काम का उत्पादन।

    सेलेनियम/कार्यात्मक परीक्षणों को शामिल करते समय हमेशा डबल कवरेज होगा क्योंकि आप इन अकेले भरोसा नहीं कर सकते क्योंकि वे दौड़ने में बहुत धीमी हैं। हालांकि, कार्यात्मक परीक्षणों को सभी कोड को कवर करने की आवश्यकता नहीं है, केवल कोर कार्यक्षमता पर्याप्त हो सकती है, क्योंकि कोड को इकाई/एकीकरण परीक्षणों द्वारा कवर किया गया है।