2012-01-17 17 views
11

का उपयोग कर नियंत्रक वर्ग के लिए यूनिट टेस्ट केस कैसे लिखें, मैं मॉकिटो और जुनीट के लिए बहुत नया हूं और मैं टीडीडी करने का सही तरीका सीखने की कोशिश करता हूं। मुझे उदाहरण के जोड़ों की आवश्यकता है ताकि मैं मॉकिटोमॉकिटो

का उपयोग कर यूनिट टेस्ट लिख सकूं, मेरे नियंत्रक वर्ग के बाद फ़ाइल अपलोड करें और इस फ़ाइल इनपुट पर कुछ कार्रवाई करें।

@Controller 
@RequestMapping("/registration") 
public class RegistrationController { 

    @Autowired 
    private RegistrationService RegistrationService; 

    @Value("#{Properties['uploadfile.location']}") 
    private String uploadFileLocation; 

    public RegistrationController() { 

    } 

    @RequestMapping(method = RequestMethod.GET) 
    public String getUploadForm(Model model) { 
     model.addAttribute(new Registration()); 
     return "is/Registration"; 
    } 

    @RequestMapping(method = RequestMethod.POST) 
    public String create(Registration registration, BindingResult result,ModelMap model) 
      throws NumberFormatException, Exception { 

     File uploadedFile = uploadFile(registration); 
     List<Registration> userDetails = new ArrayList<Registration>(); 
     processUploadedFile(uploadedFile,userDetails); 

     model.addAttribute("userDetails", userDetails); 

     return "registration"; 
    } 

    private File uploadFile(Registration registration) { 

     Date dt = new Date(); 
     SimpleDateFormat format = new SimpleDateFormat("MM_dd_yyyy_HH_mm_ss"); 
     File uploadedFile = new File(uploadFileLocation 
       + registration.getFileData().getOriginalFilename() + "." 
       + format.format(dt)); 

      registration.getFileData().transferTo(uploadedFile); 

     return uploadedFile; 
    } 

    private void processUploadedFile(File uploadedFile, List<Registration> userDetails) 
      throws NumberFormatException, Exception { 

     registrationService.processFile(uploadedFile, userDetails); 
    } 

} 

कोई भी शरीर कृपया कुछ उदाहरण सुझा सकता है कि मैकिटो का उपयोग करके मैं इसके लिए टेस्ट केस कैसे लिख सकता हूं?

संपादित मैं लिख परीक्षण वर्ग निम्नलिखित लेकिन कैसे आगे

@RunWith(MockitoJUnitRunner.class) 
@ContextConfiguration(locations = { "/META-INF/spring/applicationContext.xml"}) 
public class BulkRegistrationControllerTest { 

    @InjectMocks 
    private RegistrationService registrationService= new RegistrationServiceImpl(); 
    @Mock 
    private final ModelMap model=new ModelMap(); 

    @InjectMocks 
    private ApplicationContext applicationContext; 

    private static MockHttpServletRequest request; 
    private static MockHttpServletResponse response; 

    private static RegistrationController registrationController; 

    @BeforeClass 
    public static void init() { 

      request = new MockHttpServletRequest(); 
      response = new MockHttpServletResponse();   
      registrationController = new RegistrationController(); 

    } 
    public void testCreate() 
    { 
     final String target = "bulkRegistration"; 
     BulkRegistration bulkRegistration=new BulkRegistration(); 
     final BindingResult result=new BindingResult();  

     String nextPage=null;  
     nextPage = bulkRegistrationController.create(bulkRegistration, result, model); 
     assertEquals("Controller is not requesting the correct form",nextPage, 
       target); 

    } 

} 
+0

मैं एक ऐसी ही प्रश्न पूछा था यहाँ> http://stackoverflow.com/questions/9138555/spring-framework-test-restful-web-service-controller-offline-ie-no-server-n वहाँ पोस्ट 2 से जुड़े 2 अन्य प्रश्न हैं। मैं रीस्ट कंट्रोलर का परीक्षण करने के लिए ** वसंत-परीक्षण-एमवीसी ** ढांचे का उपयोग कर रहा हूं। इसलिए, उम्मीद है कि मेरे प्रश्नों में चर्चा किए गए एवर/कोड आपको मदद करेंगे। सौभाग्य! – jsf

उत्तर

13

नीचे दिए कुछ आप अपने परीक्षण में पार कर गए हैं लगता है। एकीकरण परीक्षण और इकाई परीक्षण हैं। एकीकरण परीक्षण सबकुछ (या लगभग सबकुछ) का परीक्षण करेगा, जो सभी हुक अप होते हैं - इसलिए आप वास्तविक लोगों के बहुत करीब स्प्रिंग कॉन्फ़िगरेशन फ़ाइलों का उपयोग करते हैं और ऑब्जेक्ट के वास्तविक उदाहरण परीक्षण के तहत आपकी कक्षा में इंजेक्शन दिए जाते हैं। यही कारण है कि ज्यादातर मैं क्या @ContextConfiguration का उपयोग करें, लेकिन मैं का उपयोग करें कि @RunWith (SpringJUnit4ClassRunner.class) के संयोजन में

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

तो, मिनी-पाठ समाप्त हो गया। यहां बताया गया है कि मैं आपकी परीक्षा कक्षा को फिर से लिखूंगा (एक अतिरिक्त उदाहरण के साथ और रास्ते में टिप्पणी की)।

@RunWith(MockitoJUnitRunner.class) 
public class RegistrationControllerTest { 

    // Create an instance of what you are going to test. 
    // When using the @InjectMocks annotation, you must create the instance in 
    // the constructor or in the field declaration. 
    @InjectMocks 
    private RegistrationController controllerUT = new RegistrationController(); 

    // The @Mock annotation creates the mock instance of the class and 
    // automatically injects into the object annotated with @InjectMocks (if 
    // possible). 
    @Mock 
    private RegistrationService registrationService; 
    // This @Mock annotation simply creates a mock instance. There is nowhere to 
    // inject it. Depending on the particular circumstance, it may be better or 
    // clearer to instantiate the mock explicitly in the test itself, but we're 
    // doing it here for illustration. Also, I don't know what your real class 
    // is like, but it may be more appropriate to just instantiate a real one 
    // than a mock one. 
    @Mock 
    private ModelMap model; 
    // Same as above 
    @Mock 
    private BulkRegistration bulkRegistration; 
    // Same as above 
    @Mock 
    private FileData fileData; 

    @Before 
    public void setUp() { 
     // We want to make sure that when we call getFileData(), it returns 
     // something non-null, so we return the mock of fileData. 
     when(bulkRegistration.getFileData()).thenReturn(fileData); 
    } 

    /** 
    * This test very narrowly tests the correct next page. That is why there is 
    * so little expectation setting on the mocks. If you want to test other 
    * things, such as behavior when you get an exception or having the expected 
    * filename, you would write other tests. 
    */ 
    @Test 
    public void testCreate() throws Exception { 
     final String target = "bulkRegistration"; 
     // Here we create a default instance of BindingResult. You don't need to 
     // mock everything. 
     BindingResult result = new BindingResult(); 

     String nextPage = null; 
     // Perform the action 
     nextPage = controllerUT.create(bulkRegistration, result, model); 
     // Assert the result. This test fails, but it's for the right reason - 
     // you expect "bulkRegistration", but you get "registration". 
     assertEquals("Controller is not requesting the correct form", nextPage, 
       target); 

    } 

    /** 
    * Here is a simple example to simulate an exception being thrown by one of 
    * the collaborators. 
    * 
    * @throws Exception 
    */ 
    @Test(expected = NumberFormatException.class) 
    public void testCreateWithNumberFormatException() throws Exception { 
     doThrow(new NumberFormatException()).when(registrationService) 
       .processFile(any(File.class), anyList()); 
     BindingResult result = new BindingResult(); 
     // Perform the action 
     controllerUT.create(bulkRegistration, result, model); 
    } 
} 
+0

इसके लिए काम करने के लिए याद रखें पीओएम को spec के कार्यान्वयन को जोड़ने के लिए, उदाहरण के लिए: ग्लासफ़िश-एम्बेडेड-सब, अन्यथा आपके पास अनुपस्थित कोड त्रुटि होगी। – Sergio

2

असली सवाल आगे बढ़ने के लिए है: कैसे सेटअप जो स्प्रिंग उपयोग कर रहा है अपने आवेदन के परीक्षण वातावरण के लिए? इस सवाल का जवाब सरल नहीं है, यह वास्तव में इस बात पर निर्भर करता है कि आपका वेब एप्लिकेशन कैसे काम करता है।

आपको सबसे पहले जावा वेब एप्लिकेशन को ज्यूनिट करने के तरीके पर ध्यान देना चाहिए, फिर मैकिटो का उपयोग कैसे करें।

1

मॉकिटो एक मॉकिंग फ्रेमवर्क है जिसका उपयोग वस्तुओं को नकल करने के लिए किया जाता है। यह आमतौर पर व्यवहार्य होता है जब आप किसी विधि का परीक्षण कर रहे हैं जो निर्भर करता है और किसी अन्य ऑब्जेक्ट के विधि परिणाम पर निर्भर करता है। उदाहरण के लिए, जब आप अपनी निर्माण विधि का परीक्षण करते हैं, तो आप uploadedFile वैरिएबल को मॉक करना चाहते हैं, क्योंकि यहां आप परीक्षण करने में रुचि नहीं रखते हैं कि uploadFile(Registration registration) सही तरीके से काम कर रहा है (आप इसे किसी अन्य परीक्षण में जांचते हैं), लेकिन आप परीक्षण करने में रुचि रखते हैं यदि विधि अपलोड की गई फ़ाइल को संसाधित कर रही है और यदि यह मॉडल में details जोड़ रही है। अपलोड फ़ाइल का नकल करने के लिए, आप जा सकते हैं: when(RegistrationController.uploadFile(anyObject()).thenReturn(new File());

लेकिन फिर आप देखते हैं कि यह एक डिज़ाइन समस्या दिखाता है। आपकी विधि uploadFile() नियंत्रक में नहीं रहनी चाहिए, बल्कि इसके बजाय किसी अन्य उपयोगिता वर्ग में। और फिर आप नियंत्रक के बजाय उस उपयोगिता वर्ग को @ मॉक कर सकते हैं।

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

1

अपने कोड नमूना को देखते हुए ऊपर मैं कुछ मुद्दों देखें:

  1. Mockito का उपयोग कर के बिंदु अपने वर्ग की निर्भरता उपहास करने के लिए है। यह आपको एक साधारण जुनीट टेस्ट केस का उपयोग करने में सक्षम करेगा। इसलिए @Context कॉन्फ़िगरेशन का उपयोग करने की कोई आवश्यकता नहीं है। आप नए ऑपरेटर का उपयोग करके परीक्षण की जा रही कक्षा को तुरंत चालू करने में सक्षम होना चाहिए और फिर आवश्यक निर्भरता प्रदान करना चाहिए।

  2. आप अपनी पंजीकरण सेवा प्रदान करने के लिए ऑटोवॉयरिंग का उपयोग कर रहे हैं। इस सेवा के एक नकली उदाहरण को इंजेक्ट करने के लिए आपको स्प्रिंग परीक्षण निजी फ़ील्ड एक्सेस यूटिलिटीज का उपयोग करने की आवश्यकता होगी।

  3. मैं आपके कोड से नहीं देख सकता कि पंजीकरण सेवा एक इंटरफ़ेस है या नहीं। यदि ऐसा नहीं है तो आपको इसे मजाक करने में समस्याएं आ रही हैं।

0

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

1

मैं Mockito से परिचित नहीं हूँ (क्योंकि मैं JMock का उपयोग करें), लेकिन mocks के साथ परीक्षण लेखन के सामान्य दृष्टिकोण एक समान है।

सबसे पहले आप परीक्षण (कट) के तहत वर्ग का एक उदाहरण (RegistrationController) की जरूरत है। यह एक नकली नहीं होना चाहिए - क्योंकि आप इसका परीक्षण करना चाहते हैं।

getUploadForm परीक्षण के लिए CUT-instance को किसी भी निर्भरता की आवश्यकता नहीं है, ताकि आप इसे new RegistrationController के माध्यम से बना सकें।

तो फिर तुम एक परीक्षण टोपी इस

RegistrationController controller = new RegistrationController(); 
Model model = new Model(); 
String result = controller(model); 
assertEquals("is/Registration", result); 
assertSomeContstrainsFormodel 

आसान था कि जैसे एक सा लग रहा है होना चाहिए।

अगली विधि जिसे आप परीक्षण करना चाहते हैं create विधि है। यह बहुत मुश्किल है। मुझे लगता है कि समस्या पर चर्चा नहीं होगी -

  • आप आप परीक्षा में फ़ाइलें (उन्हें बाद में हटाना) को संभालने की ज़रूरत पैरामीटर वस्तुओं (BindingResult) के कहने के लिए थोड़ा और अधिक जटिल
  • हो सकता है की जरूरत है। लेकिन आपको इसके बजाय परीक्षण के लिए अस्थायी फ़ाइलों का उपयोग करने के तरीके के बारे में सोचना चाहिए।
  • आप दोनों चर registrationService और uploadFileLocation का उपयोग करते हैं - यह दिलचस्प हिस्सा है।

uploadFileLocation केवल एक फ़ील्ड है जिसे परीक्षण में सेट किया जाना चाहिए। सबसे आसान तरीका टेस्ट में दर्ज किए गए सेट को सेट करने के लिए एक (गेटर और) सेटर जोड़ना होगा। आप इस क्षेत्र को सेट करने के लिए org.springframework.test.util.ReflectionTestUtils का भी उपयोग कर सकते हैं। - दोनों तरीकों से पेशेवर और conns है।

अधिक दिलचस्प registrationService है। यह एक नकली होना चाहिए! आपको उस वर्ग के लिए एक मॉक बनाने की आवश्यकता है, और उसके बाद CUT उदाहरण में उस नकली "इंजेक्ट करें"। uploadFileLocation के लिए आपके पास कम से कम दो विकल्प हैं।

फिर आपको नकली के लिए अपवादों को परिभाषित करने की आवश्यकता है: registrationService.processFile(uploadedFile, userDetails) सही फ़ाइल और उपयोगकर्ता विवरण के साथ आवेदित है। (इस अपवाद को कितना सटीक परिभाषित किया गया है मॉकिटो का हिस्सा है - और मेरे पास पर्याप्त जानकारी नहीं है)।

फिर आपको जिस विधि को आप परीक्षण करना चाहते हैं उसे आमंत्रित करने की आवश्यकता है।

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

2

यह निश्चित रूप से Mockito (या JMock) के साथ उनकी निर्भरता मजाक के रूप में jherricks ऊपर से पता चला द्वारा वसंत MVC नियंत्रकों के लिए शुद्ध इकाई परीक्षण लिखने के लिए संभव है। चुनौती यह है कि एनोटेटेड पीओजेओ नियंत्रकों के साथ वहां बहुत कुछ है जो अनचाहे रहता है - अनिवार्य रूप से सबकुछ जो एनोटेशन में व्यक्त किया जाता है और जब नियंत्रक को बुलाया जाता है तो ढांचे द्वारा किया जाता है।

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

0

इसे आजमाएं।

 
@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "/META-INF/spring/applicationContext.xml"}) 
public class BulkRegistrationControllerTest { 

    @Mock 
    private RegistrationService registrationService; 

    //Controller that is being tested. 
    @Autowired 
    @InjectMocks 
    private RegistrationController registrationController; 

    @Before 
    public void setUp() { 
     MockitoAnnotations.initMocks(this); 
     ... 
    } 
    ... 
संबंधित मुद्दे