2013-05-07 6 views
32

मेरे पास एक घटक सेटअप है जो अनिवार्य रूप से किसी एप्लिकेशन के लिए लॉन्चर है। यह बहुत तरह कॉन्फ़िगर किया गया है:परीक्षण के दौरान @Autowired निजी क्षेत्र इंजेक्शन

@Component 
public class MyLauncher { 
    @Autowired 
    MyService myService; 

    //other methods 
} 

MyService @Service स्प्रिंग टिप्पणी के साथ टिप्पणी की जाती है और किसी भी मुद्दे के बिना मेरे लांचर वर्ग में autowired है।

मैं MyLauncher के लिए कुछ JUnit परीक्षण मामलों में लिखने के लिए, ऐसा करने के लिए मैं इस तरह एक वर्ग शुरू कर दिया चाहते हैं:

public class MyLauncherTest 
    private MyLauncher myLauncher = new MyLauncher(); 

    @Test 
    public void someTest() { 

    } 
} 

मैं MyService के लिए एक नकली वस्तु बना सकते हैं और अपने परीक्षण कक्षा में myLauncher को इसकी सुई कर सकते हैं ? मेरे पास वर्तमान में मेरे लॉन्चर में गेटर या सेटर नहीं है क्योंकि स्प्रिंग ऑटोवॉयरिंग को संभालने में है। यदि संभव हो, तो मैं गेटर्स और सेटर्स को जोड़ना नहीं चाहता हूं। क्या मैं टेस्ट केस को @Before इनिट विधि का उपयोग कर ऑटोवॉयर वैरिएबल में नकली ऑब्जेक्ट इंजेक्ट करने के लिए कह सकता हूं?

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

मैं नकली वस्तुओं के लिए मॉकिटो का उपयोग करने की उम्मीद कर रहा हूं। अतीत में मैंने org.mockito.Mockito का उपयोग करके और Mockito.mock(MyClass.class)

के साथ मेरी ऑब्जेक्ट्स बनाकर बहुत कुछ किया है। इस link

पर

उत्तर

48

आप बिल्कुल mocks MyLauncher पर अपने परीक्षण में इंजेक्षन कर सकते हैं। मुझे यकीन है कि यदि आप दिखाते हैं कि आप किस मॉकिंग फ्रेमवर्क का उपयोग कर रहे हैं तो आप उत्तर देने के लिए जल्दी होंगे। मॉकिटो के साथ मैं @RunWith (MockitoJUnitRunner.class) का उपयोग करके और myLauncher के लिए एनोटेशन का उपयोग करने में देखता हूं। यह नीचे की तरह कुछ दिखता है।

@RunWith(MockitoJUnitRunner.class) 
public class MyLauncherTest 
    @InjectMocks 
    private MyLauncher myLauncher = new MyLauncher(); 

    @Mock 
    private MyService myService; 

    @Test 
    public void someTest() { 

    } 
} 
+0

@RunWith का उपयोग करने के बीच क्या अंतर है .... और इसका उपयोग न करें? – jpganz18

+0

@ jpganz18 जूनिट के साथ आप सामान्य रूप से इसका उपयोग करते हैं, यह प्रत्येक विधि – fd8s0

+0

से पहले MockitoAnnotations.initMocks को कॉल करने जैसा है, मैं अभी इस धावक का उपयोग कर रहा हूं: @RunWith (SpringRunner.class) क्या मैं MockitoJUnitRunner को प्रतिस्थापित कर सकता हूं? यदि नहीं, तो इसके बिना मोक्स इंजेक्ट करने का कोई तरीका है? (मैं वास्तव में नकली वस्तुओं का उपयोग नहीं कर रहा हूं। मैं उसी बीन्स को इंजेक्ट करना चाहता हूं जो एप्लिकेशन का उपयोग करता है।) – MiguelMunoz

1

देखो फिर अपने परीक्षण का मामला लिखने के रूप में

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration({"/applicationContext.xml"}) 
public class MyLauncherTest{ 

@Resource 
private MyLauncher myLauncher ; 

    @Test 
    public void someTest() { 
     //test code 
    } 
} 
+0

वसंत संदर्भ लोड करने का यह सही तरीका है !! लेकिन मुझे लगता है कि आप बेहतर परीक्षणों के लिए एक टेस्ट संदर्भ बनाते हैं .. –

+0

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

+0

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

10

कभी-कभी आप सेटअप करने के लिए अपने testcase निर्माता या सेटर आधारित इंजेक्शन का उपयोग करने के अपने @Component refactor कर सकते हैं (आप कर सकते हैं और अभी भी @Autowired पर भरोसा करते हैं)। अब, आप अपने परीक्षण पूरी तरह से एक मजाक रूपरेखा के बिना बजाय परीक्षण स्टब्स को लागू करने (जैसे मार्टिन फाउलर की MailServiceStub) बना सकते हैं:

@Component 
public class MyLauncher { 

    private MyService myService; 

    @Autowired 
    MyLauncher(MyService myService) { 
     this.myService = myService; 
    } 

    // other methods 
} 

public class MyServiceStub implements MyService { 
    // ... 
} 

public class MyLauncherTest 
    private MyLauncher myLauncher; 
    private MyServiceStub myServiceStub; 

    @Before 
    public void setUp() { 
     myServiceStub = new MyServiceStub(); 
     myLauncher = new MyLauncher(myServiceStub); 
    } 

    @Test 
    public void someTest() { 

    } 
} 

विशेष रूप से उपयोगी है, तो परीक्षण और परीक्षण के तहत वर्ग एक ही पैकेज क्योंकि में स्थित है इस तकनीक तो आप अन्य वर्गों को इसे एक्सेस करने से रोकने के लिए डिफ़ॉल्ट, package-private एक्सेस संशोधक का उपयोग कर सकते हैं। ध्यान दें कि आपके पास अभी भी src/main/java में आपका उत्पादन कोड हो सकता है लेकिन src/main/test निर्देशिका में आपके परीक्षण।


आप Mockito की तरह तो आप MockitoJUnitRunner सराहना करेंगे।यह तुम क्या करने की अनुमति देता है "जादू" @Manuel तरह बातें आप से पता चला है:

@RunWith(MockitoJUnitRunner.class) 
public class MyLauncherTest 
    @InjectMocks 
    private MyLauncher myLauncher; // no need to call the constructor 

    @Mock 
    private MyService myService; 

    @Test 
    public void someTest() { 

    } 
} 

वैकल्पिक रूप से, आप डिफ़ॉल्ट JUnit धावक एक setUp() विधि में Mockito प्रारंभ एनोटेट मान जाने के लिए इस्तेमाल करते हैं और कॉल कर सकते हैं MockitoAnnotations.initMocks()। आप @InitMocks के जावडोक में और blog post में और अधिक जानकारी प्राप्त कर सकते हैं जो मैंने लिखा है।

12

स्वीकृत उत्तर (MockitoJUnitRunner और @InjectMocks का उपयोग करें) बहुत अच्छा है। लेकिन यदि आप कुछ और हल्के वजन (कोई विशेष जुनीट धावक) नहीं चाहते हैं, और विशेष रूप से कभी-कभी उपयोग के लिए कम "जादुई" (अधिक पारदर्शी) चाहते हैं, तो आप सीधे आत्मनिरीक्षण का उपयोग करके निजी फ़ील्ड सेट कर सकते हैं। org.springframework.test.util.ReflectionTestUtils

उपयोग काफी सीधा है::

आप वसंत का उपयोग करते हैं, तो आप पहले से ही इस के लिए एक उपयोगिता वर्ग है

ReflectionTestUtils.setField(myLauncher, "myService", myService); 

पहला तर्क अपने लक्ष्य सेम है, दूसरा का नाम है (आमतौर पर निजी) फ़ील्ड, और अंतिम इंजेक्ट करने का मूल्य है।

यदि आप वसंत का उपयोग नहीं करते हैं, तो ऐसी उपयोगिता विधि को लागू करने के लिए यह काफी छोटा है। मुझे यह स्प्रिंग क्लास मिला है:

public static void setPrivateField(Object target, String fieldName, Object value){ 
     try{ 
      Field privateField = target.getClass().getDeclaredField(fieldName); 
      privateField.setAccessible(true); 
      privateField.set(target, value); 
     }catch(Exception e){ 
      throw new RuntimeException(e); 
     } 
    } 
1

मैं वसंत के लिए एक नया उपयोगकर्ता हूं। मुझे इसके लिए एक अलग समाधान मिला। प्रतिबिंब का उपयोग करना और सार्वजनिक आवश्यक फ़ील्ड बनाना और नकली वस्तुओं को असाइन करना।

यह मेरा ऑथ नियंत्रक है और इसमें कुछ स्वचालित निजी गुण हैं।

@RestController 
public class AuthController { 

    @Autowired 
    private UsersDAOInterface usersDao; 

    @Autowired 
    private TokensDAOInterface tokensDao; 

    @RequestMapping(path = "/auth/getToken", method = RequestMethod.POST) 
    public @ResponseBody Object getToken(@RequestParam String username, 
      @RequestParam String password) { 
     User user = usersDao.getLoginUser(username, password); 

     if (user == null) 
      return new ErrorResult("Kullanıcıadı veya şifre hatalı"); 

     Token token = new Token(); 
     token.setTokenId("aergaerg"); 
     token.setUserId(1); 
     token.setInsertDatetime(new Date()); 
     return token; 
    } 
} 

और यह ऑथकंट्रोलर के लिए मेरा जूनिट परीक्षण है। मैं सार्वजनिक की जरूरत निजी संपत्तियों बनाने और उन्हें और रॉक :)

public class AuthControllerTest { 

    @Test 
    public void getToken() { 
     try { 
      UsersDAO mockUsersDao = mock(UsersDAO.class); 
      TokensDAO mockTokensDao = mock(TokensDAO.class); 

      User dummyUser = new User(); 
      dummyUser.setId(10); 
      dummyUser.setUsername("nixarsoft"); 
      dummyUser.setTopId(0); 

      when(mockUsersDao.getLoginUser(Matchers.anyString(), Matchers.anyString())) // 
        .thenReturn(dummyUser); 

      AuthController ctrl = new AuthController(); 

      Field usersDaoField = ctrl.getClass().getDeclaredField("usersDao"); 
      usersDaoField.setAccessible(true); 
      usersDaoField.set(ctrl, mockUsersDao); 

      Field tokensDaoField = ctrl.getClass().getDeclaredField("tokensDao"); 
      tokensDaoField.setAccessible(true); 
      tokensDaoField.set(ctrl, mockTokensDao); 

      Token t = (Token) ctrl.getToken("test", "aergaeg"); 

      Assert.assertNotNull(t); 

     } catch (Exception ex) { 
      System.out.println(ex); 
     } 
    } 

} 

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

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