मॉकिटो: निजी @Autowired फ़ील्ड में वास्तविक ऑब्जेक्ट इंजेक्ट करें


190

मैं मॉकिटो @Mockऔर @InjectMocksएनोटेशन का उपयोग निजी क्षेत्रों में निर्भरता को इंजेक्ट करने के लिए कर रहा हूं, जो स्प्रिंग के साथ एनोटेट हैं @Autowired:

@RunWith(MockitoJUnitRunner.class)
public class DemoTest {
    @Mock
    private SomeService service;

    @InjectMocks
    private Demo demo;

    /* ... */
}

तथा

public class Demo {

    @Autowired
    private SomeService service;

    /* ... */
}

अब मैं वास्तविक वस्तुओं को निजी @Autowiredक्षेत्रों में (बिना सेटल किए) इंजेक्ट करना चाहूंगा । क्या यह संभव है या तंत्र केवल मोक्स को इंजेक्ट करने तक सीमित है?


5
आम तौर पर जब आप चीजों का मजाक उड़ा रहे होते हैं, तो इसका मतलब है कि आप ठोस वस्तु की ज्यादा परवाह नहीं करते हैं; कि आप वास्तव में केवल नकली वस्तु के व्यवहार की परवाह करते हैं। शायद आप इसके बजाय एक एकीकरण परीक्षण करना चाहते हैं? या, क्या आप एक तर्क प्रदान कर सकते हैं कि आप एक साथ रहने के लिए नकली और ठोस वस्तुओं को क्यों चाहते हैं?
मकोतो

2
ठीक है, मैं विरासत कोड के साथ काम कर रहा हूं और यह बहुत कुछ (...) तब होगा। कुछ एनपीई और इस तरह से रोकने के लिए मॉक सेटअप करने के लिए कथन (...)। दूसरी ओर, एक वास्तविक वस्तु को इसके लिए सुरक्षित रूप से इस्तेमाल किया जा सकता है। इसलिए नकली के साथ-साथ वास्तविक वस्तुओं को इंजेक्ट करने का विकल्प होना बहुत आसान होगा। भले ही यह एक कोड गंध हो, मैं इस विशेष मामले में इसे उचित मानता हूं।
user2286693

विधि MockitoAnnotations.initMocks(this);में मत भूलना @Before। मुझे पता है कि यह सीधे मूल प्रश्न से संबंधित नहीं है, लेकिन बाद में आने वाले किसी भी व्यक्ति के लिए, जिसे इस रन करने योग्य बनाने के लिए जोड़ना होगा।
कूगा

7
@ कूगा: यदि आप ज्यूनिट के लिए मॉकिटो रनर का उपयोग करते हैं, ( @RunWith(MockitoJUnitRunner.class)), आपको लाइन की आवश्यकता नहीं हैMockitoAnnotations.initMocks(this);
क्लिंट ईस्टवुड

1
धन्यवाद-- मुझे कभी नहीं पता था कि और हमेशा दोनों निर्दिष्ट कर रहे हैं
Cug

जवाबों:


304

@Spyएनोटेशन का उपयोग करें

@RunWith(MockitoJUnitRunner.class)
public class DemoTest {
    @Spy
    private SomeService service = new RealServiceImpl();

    @InjectMocks
    private Demo demo;

    /* ... */
}

मॉकिटो सभी क्षेत्रों के होने @Mockया @Spyएनोटेशन पर विचार करेगा, क्योंकि संभावित उम्मीदवारों को @InjectMocksएनोटेशन के साथ एनोटेट में इंजेक्ट किया जाएगा । उपरोक्त मामले में 'RealServiceImpl'उदाहरण 'डेमो' में अंतःक्षिप्त हो जाएगा।

अधिक जानकारी के लिए देखें

Mockito-घर

@Spy

@Mock


9
+1: मेरे लिए काम किया ... स्ट्रिंग वस्तुओं को छोड़कर। मॉकिटो की शिकायत है:Mockito cannot mock/spy following: - final classes - anonymous classes - primitive types
एड्रियन प्रोक

धन्यवाद यह मेरे लिए भी काम किया :) वास्तविक कार्यान्वयन के लिए प्रॉक्सी का उपयोग करने के लिए नकली का उपयोग करें जासूसी
स्वार अग्रवाल

धन्यवाद! Thats वास्तव में मैं क्या जरूरत है!
nterry

2
मेरे मामले में, मॉकिटो एक जासूस को इंजेक्शन नहीं दे रहा है । हालांकि यह एक मॉक इंजेक्ट करता है। मैदान निजी और बिना सेटर वाला है।
विटुएल

8
BTW, कोई ज़रूरत नहीं है new RealServiceImpl(), @Spy private SomeService service;वैसे भी जासूसी करने से पहले डिफ़ॉल्ट कंस्ट्रक्टर का उपयोग करके एक वास्तविक ऑब्जेक्ट बनाता है।
parxier

20

इसके अलावा @Dev ब्लेंक किए गए उत्तर में, यदि आप एक मौजूदा बीन का उपयोग करना चाहते हैं जो स्प्रिंग द्वारा बनाया गया था तो कोड को संशोधित किया जा सकता है:

@RunWith(MockitoJUnitRunner.class)
public class DemoTest {

    @Inject
    private ApplicationContext ctx;

    @Spy
    private SomeService service;

    @InjectMocks
    private Demo demo;

    @Before
    public void setUp(){
        service = ctx.getBean(SomeService.class);
    }

    /* ... */
}

इस तरह आपको परीक्षणों को काम करने के लिए अपना कोड बदलने (किसी अन्य निर्माता को जोड़ने) की आवश्यकता नहीं है।


2
@ क्या आप विस्तृत कर सकते हैं?
योज मेंडा

1
यह किस लाइब्रेरी से आता है, मैं केवल InjectMocks को org.mockito में देख सकता हूं
समीर

1
@sameer आयात org.mockito.InjectMocks;
योआज मेंडा

आडा को रद्द करने के लिए एक टिप्पणी जोड़ना। इसने मेरे लिए काम किया। मैं अन्य उत्तरों द्वारा सुझाए गए अनुसार "केवल फ़ील्ड इंजेक्शन का उपयोग नहीं कर सकता", इसलिए मुझे यह सुनिश्चित करना था कि Autowiredनिर्भरता से फ़ील्ड सही तरीके से बनाए गए थे।
स्क्रैम्बो

1
मैंने यह कोशिश की है। लेकिन मैं सेटअप विधि से अशक्त सूचक अपवाद प्राप्त कर रहा हूं
अखिल सुरपुरम

3

मॉकिटो एक डीआई फ्रेमवर्क नहीं है और यहां तक ​​कि डीआई फ्रेमवर्क फील्ड इंजेक्शनों पर कंस्ट्रक्टर इंजेक्शन को प्रोत्साहित करते हैं।
इसलिए आप परीक्षण के तहत कक्षा की निर्भरता निर्धारित करने के लिए सिर्फ एक निर्माता की घोषणा करते हैं:

@Mock
private SomeService serviceMock;

private Demo demo;

/* ... */
@BeforeEach
public void beforeEach(){
   demo = new Demo(serviceMock);
}

spyसामान्य मामले के लिए मॉकिटो का उपयोग करना एक भयानक सलाह है। यह परीक्षण वर्ग को भंगुर बनाता है, न कि सीधे और त्रुटि प्रवण: वास्तव में क्या मज़ाक उड़ाया जाता है? वास्तव में परीक्षण क्या है?
@InjectMocksऔर @Spyसमग्र डिजाइन को भी नुकसान पहुंचाता है क्योंकि यह वर्गों में फूला हुआ वर्ग और मिश्रित जिम्मेदारियों को प्रोत्साहित करता है।
कृपया आँख बंद करके उपयोग करने से पहले जावदोक पढ़ेंspy() (जोर मेरा नहीं है):

वास्तविक वस्तु का जासूस बनाता है। जब तक वे ठगे नहीं जाते तब तक जासूस असली तरीके कहता है । वास्तविक जासूसों को सावधानीपूर्वक और कभी-कभी इस्तेमाल किया जाना चाहिए , उदाहरण के लिए जब विरासत कोड के साथ काम करते हैं।

हमेशा की तरह आप पढ़ने जा रहे हैं partial mock warning : ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग जटिलता को अलग, विशिष्ट, SRPy ऑब्जेक्ट्स में विभाजित करके जटिलता से निपटता है। आंशिक प्रतिमान इस प्रतिमान में कैसे फिट होता है? खैर, यह सिर्फ नहीं है ... आंशिक रूप से नकली का मतलब है कि जटिलता को एक ही वस्तु पर एक अलग विधि में स्थानांतरित कर दिया गया है। ज्यादातर मामलों में, यह वह तरीका नहीं है जिससे आप अपना एप्लिकेशन डिज़ाइन करना चाहते हैं।

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


0

वसंत में एक समर्पित उपयोगिता है जिसे ReflectionTestUtilsइस उद्देश्य के लिए कहा जाता है । विशिष्ट उदाहरण लें और क्षेत्र में इंजेक्ट करें।


@Spy
..
@Mock
..

@InjectMock
Foo foo;

@BeforeEach
void _before(){
   ReflectionTestUtils.setField(foo,"bar", new BarImpl());// `bar` is private field
}

-1

मुझे पता है कि यह एक पुराना सवाल है, लेकिन स्ट्रिंग्स को इंजेक्ट करने की कोशिश करते समय हमें उसी समस्या का सामना करना पड़ा। इसलिए हमने एक JUnit5 / Mockito एक्सटेंशन का आविष्कार किया, जो वास्तव में आप चाहते हैं: https://github.com/exabrial/mockito-object-injection

संपादित करें:

@InjectionMap
 private Map<String, Object> injectionMap = new HashMap<>();

 @BeforeEach
 public void beforeEach() throws Exception {
  injectionMap.put("securityEnabled", Boolean.TRUE);
 }

 @AfterEach
 public void afterEach() throws Exception {
  injectionMap.clear();
 }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.