मॉकिटो का इंजेक्शन एक स्प्रिंग बीन में लगाता है


284

मैं JUnit के साथ यूनिट परीक्षण के प्रयोजनों के लिए एक स्प्रिंग (3+) बीन में मॉकिटो मॉक ऑब्जेक्ट इंजेक्ट करना चाहूंगा। वर्तमान में @Autowiredनिजी सदस्य फ़ील्ड पर एनोटेशन का उपयोग करके मेरी बीन निर्भरताएँ इंजेक्ट की जाती हैं।

मैंने उपयोग करने पर विचार किया है ReflectionTestUtils.setFieldलेकिन जिस सेम उदाहरण को मैं इंजेक्ट करना चाहता हूं वह वास्तव में एक प्रॉक्सी है और इसलिए लक्ष्य वर्ग के निजी सदस्य फ़ील्ड घोषित नहीं करता है। मैं निर्भरता के लिए एक सार्वजनिक सेटर बनाने की इच्छा नहीं करता हूं क्योंकि मैं परीक्षण के प्रयोजनों के लिए अपने इंटरफ़ेस को शुद्ध रूप से संशोधित करूंगा।

मैंने स्प्रिंग समुदाय द्वारा दी गई कुछ सलाह का पालन ​​किया है, लेकिन नकली का निर्माण नहीं होता है और ऑटो-वायरिंग विफल हो जाती है:

<bean id="dao" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="com.package.Dao" />
</bean>

वर्तमान में मेरे द्वारा की गई त्रुटि इस प्रकार है:

...
Caused by: org...NoSuchBeanDefinitionException:
    No matching bean of type [com.package.Dao] found for dependency:
    expected at least 1 bean which qualifies as autowire candidate for this dependency.
    Dependency annotations: {
        @org...Autowired(required=true),
        @org...Qualifier(value=dao)
    }
at org...DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(D...y.java:901)
at org...DefaultListableBeanFactory.doResolveDependency(D...y.java:770)

यदि मैं constructor-argकुछ अमान्य मान को सेट करता हूं तो अनुप्रयोग संदर्भ शुरू करते समय कोई त्रुटि नहीं होती है।


4
कृपया इस छोटे से प्राणी पर एक नज़र डालें: bitbucket.org/kubek2k/springockito/wiki/Home
kubek2k

यह बहुत साफ दृष्टिकोण है - मुझे यह पसंद है!
टीबॉट

2
आपने मुझे स्प्रिंगॉकिटो-एनोटेशन में रखा था।
युहत्सर्न


2
स्प्रिंग 4. * का उपयोग करने वालों के लिए, जनवरी 2015 तक यह नवीनतम स्प्रिंग मॉकिटो संस्करण के साथ काम नहीं करता है और परियोजना निष्क्रिय दिखाई देती है।
मुरली

जवाबों:


130

सबसे अच्छा तरीका है:

<bean id="dao" class="org.mockito.Mockito" factory-method="mock"> 
    <constructor-arg value="com.package.Dao" /> 
</bean> 

अद्यतन
संदर्भ फ़ाइल में इस मॉक को घोषित किए जाने के आधार पर किसी भी स्वतः पूर्ण फ़ील्ड से पहले सूचीबद्ध किया जाना चाहिए।


मुझे एक त्रुटि मिली: "'मॉकिटो' नाम से बीन बनाने में त्रुटि: बीन की परिभाषा सार है"
tttppp

4
@amra: वसंत ने इस मामले में लौटी वस्तु का प्रकार पता नहीं लगाया ... stackoverflow.com/q/6976421/306488
lisak

7
पता नहीं क्यों इस उत्तर को बहुत अधिक उकेरा गया है, जिसके परिणामस्वरूप बीन को स्वीकार नहीं किया जा सकता है क्योंकि इसमें गलत प्रकार है।
14

4
यदि इसे संदर्भ फ़ाइल में पहले सूचीबद्ध किया गया है, तो इसे स्वत: प्राप्त किया जा सकता है (किसी भी स्वत: प्राप्त फ़ील्ड से पहले जो इस पर निर्भर करेगा घोषित किया गया है।)
रयान वॉल्स

3
वसंत 3.2 के रूप में, सेम का क्रम अब मायने नहीं रखता है। इस ब्लॉग पोस्ट में "जेनेरिक फैक्ट्री मेथड्स" शीर्षक वाला अनुभाग देखें: spring.io/blog/2012/11/07/…
रयान वॉल्स

110
@InjectMocks
private MyTestObject testObject;

@Mock
private MyDependentObject mockedObject;

@Before
public void setup() {
        MockitoAnnotations.initMocks(this);
}

यह किसी भी नकली वस्तुओं को परीक्षण वर्ग में इंजेक्ट करेगा। इस मामले में यह testObject में mockedObject को इंजेक्ट करेगा। यह ऊपर उल्लेख किया गया था, लेकिन यहां कोड है।


1
मैं किस प्रकार की एक विशेष विधि ठूंठ सकता हूँ mockedObject?
जिम होल्डन

@Teachacher जब (mockedObject.execute) .thenReturn (objToReturn); आप या तो पहले की विधि में या अपनी परीक्षा विधि के अंदर रख सकते हैं।
चॉस्तोरी

40
FYI करें: यह दृष्टिकोण काम नहीं करेगा, अगर मैं MyTestObject में आंशिक ऑटोवेयरिंग और आंशिक मजाक करना चाहता हूं।
रसगुल्ला

9
मुझे नहीं पता कि यह उच्च मतदान क्यों नहीं है। अगर मुझे XML से संबंधित कोई और उत्तर दिखाई देता है तो मैं हर्ट करने वाला हूं।
मार्कऑफ हॉल

3
इसके बजाय आप Mockito.spy(...)इस पर उपयोग क्यों नहीं करते mockedObject? और फिर उपयोग when(mockedObject.execute).thenReturn(objToReturn)या doReturn(objToReturn).when(mockedObject).execute()। दूसरा कोई वास्तविक विधि का आह्वान नहीं करता है। आप यह भी देख सकते हैं Mockito.doCallRealMethod()प्रलेखन
टॉमाज़ Przybylski

63

मेरे पास स्प्रिंग जावा कॉन्फिग और मॉकिटो का उपयोग करके एक बहुत ही सरल समाधान है:

@Configuration
public class TestConfig {

    @Mock BeanA beanA;
    @Mock BeanB beanB;

    public TestConfig() {
        MockitoAnnotations.initMocks(this); //This is a key
    }

    //You basically generate getters and add @Bean annotation everywhere
    @Bean
    public BeanA getBeanA() {
        return beanA;
    }

    @Bean
    public BeanB getBeanB() {
        return beanB;
    }
}

4
इस दृष्टिकोण के साथ किसी कारण से, वसंत वास्तविक बीन को वैसे भी बनाने की कोशिश करता है (मॉक के बजाय) और उस पर चुटकी लेता है ... मैं क्या गलत कर रहा हूं?
डैनियल ग्रूसज़िक 9

1
मेरे पास एक ही मुद्दा है
कोरबोको एलेक्स

3
यदि आप एक वर्ग का मजाक उड़ा रहे हैं, तो वसंत नहीं, बल्कि मॉकिटो एक वास्तविक बीन को पलटने की कोशिश करता है। यदि आपके पास कोई बीन्स है जो परीक्षणों में नकली हैं, तो उन्हें एक इंटरफ़ेस का कार्यान्वयन होना चाहिए, और उस इंटरफ़ेस के माध्यम से इंजेक्ट किया जाना चाहिए। यदि आप इंटरफ़ेस (क्लास के बजाय) को मॉक करते हैं, तो मॉकिटो उस क्लास को इंस्टेंट करने की कोशिश नहीं करेगा।
डैनियल ग्रूसज़िक

7
मुद्दा क्या है? एनोटेट फ़ील्ड और कंस्ट्रक्टर को क्यों जोड़ें initMocks? क्यों नहीं बस return Mockito.mock(BeanA.class)में getBeanA? इस तरह यह सरल है और कम कोड है। मैं क्या खो रहा हूँ?
ओलेग

1
@ यदि ऐसा लगता है कि आपके पास अपना स्वयं का समाधान है, जिसे आपको संभवतः उत्तर के रूप में पोस्ट करना चाहिए, ताकि समुदाय उस पर वोट कर सके।
दाऊद इब्न करीम

48

दिया हुआ:

@Service
public class MyService {
    @Autowired
    private MyDAO myDAO;

    // etc
}

आपके पास वह वर्ग हो सकता है जिसका परीक्षण स्वतः-लोडिंग के माध्यम से किया जा रहा है, मॉकिटो के साथ निर्भरता का मज़ाक उड़ाएं, और फिर परीक्षण किए जा रहे वर्ग में मॉक को इंजेक्ट करने के लिए स्प्रिंग के रिफ्लेक्शनटाइस्टिल्स का उपयोग करें।

@ContextConfiguration(classes = { MvcConfiguration.class })
@RunWith(SpringJUnit4ClassRunner.class)
public class MyServiceTest {
    @Autowired
    private MyService myService;

    private MyDAO myDAOMock;

    @Before
    public void before() {
        myDAOMock = Mockito.mock(MyDAO.class);
        ReflectionTestUtils.setField(myService, "myDAO", myDAOMock);
    }

    // etc
}

कृपया ध्यान दें कि स्प्रिंग 4.3.1 से पहले, यह विधि एक प्रॉक्सी के पीछे सेवाओं के साथ काम नहीं करेगी ( उदाहरण के लिए @Transactional, या Cacheable, के साथ एनोटेट )। यह SPR-14050 द्वारा तय किया गया है ।

पहले के संस्करणों के लिए, एक समाधान प्रॉक्सी को खोलना है, जैसा कि वहां वर्णित है: लेन-देन एनोटेशन सेवाओं को नकली होने से बचा जाता है (जो कि ReflectionTestUtils.setFieldडिफ़ॉल्ट रूप से अब होता है)


डबल @RunWith (SpringJUnit4ClassRunner.class) और मैं परीक्षण वर्ग (एक ही धावक) के लिए विभिन्न एनोटेशन का उपयोग करता हूं, लेकिन यह दृष्टिकोण मेरे लिए काम करता है, धन्यवाद।
user1317422

1
मैं बहुत प्रेरित था "कृपया ध्यान दें कि स्प्रिंग 4.3.1 से पहले, यह विधि एक प्रॉक्सी के पीछे सेवाओं के साथ काम नहीं करेगी (उदाहरण के लिए @Transactional या Cacheable के साथ एनोटेट), यह SPR-14050 द्वारा तय किया गया है"। मैं बस इस मुद्दे में भाग गया और इस शब्द को जगह देने तक कोई सुराग नहीं मिला। आपका बहुत बहुत धन्यवाद!
स्नोफ़ॉक्स

1
जब आप संपूर्ण अनुप्रयोग संदर्भ को निकाल चुके होते हैं और परीक्षण के उद्देश्य से, अपने संदर्भ में एक यादृच्छिक सेम में एक नकली इंजेक्षन करना चाहते हैं, तो यह समाधान संभालता है। मैंने इस जवाब का इस्तेमाल एक मॉड्यूल टेस्ट में अन्य मॉडल्स को REST कॉल से बचने के लिए एक फनी क्लाइंट बीन का मज़ाक उड़ाने के लिए किया। मुझे केवल InjectMock एनोटेशन काम करने के लिए मिला जब आप एक सेम में मॉक इंजेक्ट कर रहे हैं जिसे आप परीक्षण करने वाले हैं, स्प्रिंग एप्लिकेशन कॉन्फ़िगरेशन द्वारा बनाई गई बीन में नहीं।
एंड्रियास लुंडग्रेन 11

1
लगभग पूरा एक दिन बिना संदर्भ को रीसेट किए @MockBean काम करने की कोशिश में इधर-उधर भटकता रहता है और फिर मैं इस मणि के पार आ जाता हूं। वास्तव में जो मुझे चाहिए था, चीयर्स।
मैट आर

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

36

यदि आप स्प्रिंग बूट 1.4 का उपयोग कर रहे हैं, तो यह ऐसा करने का एक शानदार तरीका है। बस @SpringBootTestअपनी कक्षा और @MockBeanमैदान पर नए ब्रांड का उपयोग करें और स्प्रिंग बूट इस प्रकार का एक नकली बना देगा और इसे संदर्भ में इंजेक्ट करेगा (मूल एक को इंजेक्ट करने के बजाय):

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {

    @MockBean
    private RemoteService remoteService;

    @Autowired
    private Reverser reverser;

    @Test
    public void exampleTest() {
        // RemoteService has been injected into the reverser bean
        given(this.remoteService.someCall()).willReturn("mock");
        String reverse = reverser.reverseSomeCall();
        assertThat(reverse).isEqualTo("kcom");
    }

}

दूसरी ओर, यदि आप स्प्रिंग बूट का उपयोग नहीं कर रहे हैं या आप पिछले संस्करण का उपयोग कर रहे हैं, तो आपको थोड़ा और काम करना होगा:

एक @Configurationबीन बनाएँ जो आपके मॉक को स्प्रिंग संदर्भ में इंजेक्ट करता है:

@Configuration
@Profile("useMocks")
public class MockConfigurer {

    @Bean
    @Primary
    public MyBean myBeanSpy() {
        return mock(MyBean.class);
    }
}

@Primaryएनोटेशन का उपयोग करके आप स्प्रिंग को बता रहे हैं कि यदि कोई क्वालिफायर निर्दिष्ट नहीं किया गया है तो इस सेम की प्राथमिकता है।

सुनिश्चित करें कि आप वर्ग को एनोटेट करें @Profile("useMocks")ताकि यह नियंत्रित किया जा सके कि कौन सी कक्षाएं मॉक का उपयोग करेंगी और कौन से असली बीन का उपयोग करेंगे।

अंत में, अपने परीक्षण में, userMocksप्रोफ़ाइल सक्रिय करें :

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {Application.class})
@WebIntegrationTest
@ActiveProfiles(profiles={"useMocks"})
public class YourIntegrationTestIT {

    @Inject
    private MyBean myBean; //It will be the mock!


    @Test
    public void test() {
        ....
    }
}

यदि आप नकली लेकिन असली बीन का उपयोग नहीं करना चाहते हैं, तो केवल useMocksप्रोफ़ाइल सक्रिय न करें :

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {Application.class})
@WebIntegrationTest
public class AnotherIntegrationTestIT {

    @Inject
    private MyBean myBean; //It will be the real implementation!


    @Test
    public void test() {
        ....
    }
}

5
इस उत्तर को शीर्ष पर जाना चाहिए - @MockBean समर्थन स्प्रिंग बूट में भी स्प्रिंग-बूट के बिना उपयोग किया जा सकता है। आप इसे यूनिट परीक्षणों में उपयोग कर सकते हैं, इसलिए यह सभी वसंत अनुप्रयोगों के लिए काम करता है!
बेडरीन

2
एनोटेशन @Profile आप सेम परिभाषा पद्धति पर भी सेट कर सकते हैं, अलग विन्यास वर्ग बनाने से बचने के लिए
मार्सिन

बहुत बढ़िया जवाब! मैंने अपने पुराने-विद्यालय web.xmlऔर AnnotationConfigWebApplicationContext सेटअप के साथ इसे काम करने के लिए कुछ बदलाव किए । का इस्तेमाल किया था @WebAppConfigurationके बजाय @WebIntegrationTestऔर @ContextHierarchyसाथ @ContextConfigurationके बजाय @SpringApplicationConfiguration
UTF_or_Death

मुझे @Primaryअपने केस के लिए एनोटेशन जोड़ना था , क्योंकि मेरे अंदर एक फेलिंग कॉल @PostConstructथा जिसे मैं मॉक करना चाहता था, लेकिन @PostConstructमेरे मॉक से पहले बीन बनाई गई थी, इसलिए उसने मॉक का उपयोग नहीं किया (जब तक कि मैंने जोड़ा नहीं @Primary)।
हेलले

19

चूंकि 1.8.3 मॉकिटो है @InjectMocks- यह अविश्वसनीय रूप से उपयोगी है। मेरे JUnit परीक्षण कर रहे हैं और मैं निर्माण वस्तुओं है कि संतुष्ट सभी वर्ग के लिए निर्भरता परीक्षण किया जा रहा है, जो सभी इंजेक्ट किया जाता है जब निजी सदस्य के साथ टिप्पणी की जाती है ।@RunWithMockitoJUnitRunner@Mock@InjectMocks

मैं अब केवल एकीकरण परीक्षणों @RunWithके SpringJUnit4Runnerलिए।

मैं ध्यान दूंगा कि यह List<T>स्प्रिंग के समान तरीके से इंजेक्ट करने में सक्षम नहीं लगता है । यह केवल एक मॉक ऑब्जेक्ट के लिए दिखता है जो संतुष्ट करता है List, और मॉक ऑब्जेक्ट की सूची को इंजेक्ट नहीं करेगा। मेरे लिए वर्कअराउंड @Spyमैन्युअल रूप से तात्कालिक सूची के विरुद्ध और मैन्युअल रूप से मॉक ऑब्जेक्ट को इकाई परीक्षण के लिए उस सूची में उपयोग करना था। हो सकता है कि यह जानबूझकर किया गया था, क्योंकि यह निश्चित रूप से मुझे ध्यान देने के लिए मजबूर किया गया था कि एक साथ मजाक किया जा रहा था।


हाँ यह सबसे अच्छा तरीका है। स्प्रिंगकिटो वास्तव में मेरे मामले में जो भी कारण के लिए नकली इंजेक्शन नहीं करता है।
चोस्तोरी

13

अद्यतन: इस समस्या के लिए अब बेहतर, क्लीनर समाधान हैं। कृपया पहले अन्य उत्तरों पर विचार करें।

मुझे अंततः उनके ब्लॉग पर रॉनन द्वारा इसका उत्तर मिला। मुझे समस्या यह थी कि Mockito.mock(Class c)वापसी के प्रकार की घोषणा करने की विधि के कारण Object। नतीजतन, स्प्रिंग कारखाने विधि वापसी प्रकार से सेम प्रकार का अनुमान लगाने में असमर्थ है।

रोनेन का समाधान एक FactoryBeanकार्यान्वयन बनाना है जो मॉक लौटाता है। FactoryBeanइंटरफ़ेस स्प्रिंग कारखाने सेम के द्वारा बनाई गई वस्तुओं के प्रकार क्वेरी करने के लिए अनुमति देता है।

मेरी नकली सेम परिभाषा अब लग रहा है:

<bean id="mockDaoFactory" name="dao" class="com.package.test.MocksFactory">
    <property name="type" value="com.package.Dao" />
</bean>


मुझे यह समझ में नहीं आता है कि, फैक्ट्री मेथड में रिटर्न टाइप ऑब्जेक्ट होता है ... लेकिन एमरा के सॉल्यूशन में जेनेरिक रिटर्न टाइप होता है, ताकि स्प्रिंग को इसे पहचानना चाहिए ... लेकिन अमरा का सॉल्यूशन मेरे लिए काम नहीं करता है
lisak

न तो इस समाधान, वसंत फली के प्रकार है कि factoryBean से इसलिए [com.package.Dao] ... प्रकार की कोई मिलती-जुलती सेम दिया जाता है इसका अनुमान नहीं लगा है
Lisak


यह लिंक वास्तव में अभी भी काम करता है: javadevelopmentforthemasses.blogspot.com/2008/07/… बस अपने ब्राउज़र में लिंक पुनर्निर्देशन को अक्षम करें और आप अपने नए ब्लॉग पर 404 को देखने के लिए मजबूर होने के बजाय इसे देखेंगे।
लगभग

12

वसंत 3.2 के रूप में, यह अब एक मुद्दा नहीं है। स्प्रिंग अब जेनेरिक फ़ैक्टरी विधियों के परिणामों के ऑटोविंग का समर्थन करता है। इस ब्लॉग पोस्ट में "जेनेरिक फैक्ट्री मेथड्स" शीर्षक वाला भाग देखें: http://spring.io/blog/2012/11/07/spring-framework-3-2-rc1-new-testing-features/

मुख्य बिंदु यह है:

स्प्रिंग 3.2 में, फैक्ट्री के तरीकों के लिए सामान्य रिटर्न प्रकार अब ठीक से अनुमान नहीं लगाया गया है, और मोक्स के लिए टाइप करके ऑटोवेयरिंग को उम्मीद के मुताबिक काम करना चाहिए। नतीजतन, कस्टम वर्क-अराउंड जैसे कि मॉकिटोफैक्टरीबीन, ईज़ीमॉकफैक्टरीबीन या स्प्रिंगॉकिटो संभवतः अब आवश्यक नहीं हैं।

इसका मतलब है कि यह बॉक्स से बाहर काम करना चाहिए:

<bean id="dao" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="com.package.Dao" />
</bean>

9

नीचे दिए गए कोड ऑटोविंग के साथ काम करते हैं - यह सबसे छोटा संस्करण नहीं है, लेकिन उपयोगी है जब इसे केवल मानक वसंत / मॉकिटो जार के साथ काम करना चाहिए।

<bean id="dao" class="org.springframework.aop.framework.ProxyFactoryBean">
   <property name="target"> <bean class="org.mockito.Mockito" factory-method="mock"> <constructor-arg value="com.package.Dao" /> </bean> </property>
   <property name="proxyInterfaces"> <value>com.package.Dao</value> </property>
</bean> 

मेरे लिए काम किया। मुझे अपने परीक्षण में प्रॉक्सी को इस प्रकार सत्यापित करने के लिए खोलना था, जैसा कि यहाँ वर्णित है: forum.spring.io/forum/spring-projects/aop/…
Holgzn

9

यदि आप स्प्रिंग> = 3.0 का उपयोग कर रहे हैं , @Configurationतो एप्लिकेशन संदर्भ के भाग को परिभाषित करने के लिए स्प्रिंग्स एनोटेशन का उपयोग करें

@Configuration
@ImportResource("com/blah/blurk/rest-of-config.xml")
public class DaoTestConfiguration {

    @Bean
    public ApplicationService applicationService() {
        return mock(ApplicationService.class);
    }

}

यदि आप @ImportResource का उपयोग नहीं करना चाहते हैं, तो इसे दूसरे तरीके से भी किया जा सकता है:

<beans>
    <!-- rest of your config -->

    <!-- the container recognize this as a Configuration and adds it's beans 
         to the container -->
    <bean class="com.package.DaoTestConfiguration"/>
</beans>

अधिक जानकारी के लिए, स्प्रिंग-फ्रेमवर्क-संदर्भ: जावा-आधारित कंटेनर कॉन्फ़िगरेशन पर एक नज़र डालें


अच्छा है। मैंने इसका उपयोग तब किया जब मैं परीक्षण कर रहा हूं @ वास्तविक परीक्षण मामले में @Autowired है।
enkor

8

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


3
मैं आपके दृष्टिकोण को समझता हूं। हालाँकि, मैं अपने आप को इस स्थिति में एक बड़े विरासत कोड आधार पर पाता हूं जो आसानी से इसके लिए अनुमति नहीं देता है - फिर भी।
टीबॉट

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

@ लार्स - सहमत - उसी परीक्षणों के बारे में कहा जा सकता है जिससे मैं निपट रहा हूं।
टीबॉट

7

मैं मॉकिटो का उपयोग करके निम्नलिखित कर सकता हूं:

<bean id="stateMachine" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="com.abcd.StateMachine"/>
</bean>

1
उत्तर @Alexander के लिए धन्यवाद। क्या मैं पूछ सकता हूं: क्या यह सही ढंग से वायर-अप करता है? यदि ऐसा है तो आप स्प्रिंग / मॉकिटो के किन संस्करणों का उपयोग कर रहे हैं?
चायबोट

6

उपरोक्त दृष्टिकोण के आधार पर कुछ उदाहरण पोस्ट करना

वसंत के साथ:

@ContextConfiguration(locations = { "classpath:context.xml" })
@RunWith(SpringJUnit4ClassRunner.class)
public class TestServiceTest {
    @InjectMocks
    private TestService testService;
    @Mock
    private TestService2 testService2;
}

वसंत के बिना:

@RunWith(MockitoJUnitRunner.class)
public class TestServiceTest {
    @InjectMocks
    private TestService testService = new TestServiceImpl();
    @Mock
    private TestService2 testService2;
}

2

अद्यतन - नई जवाब यहाँ: https://stackoverflow.com/a/19454282/411229 । यह उत्तर केवल 3.2 से पहले स्प्रिंग संस्करणों पर लागू होता है।

मैंने इसे और अधिक निश्चित समाधान के लिए थोड़ी देर के लिए देखा है। यह ब्लॉग पोस्ट मेरी सभी जरूरतों को पूरा करने के लिए लगता है और बीन की घोषणा के आदेश पर भरोसा नहीं करता है। सारा श्रेय मटियास सेवरसन को। http://www.jayway.com/2011/11/30/spring-integration-tests-part-i-creating-mock-objects/

मूल रूप से, एक FactoryBean को लागू करें

package com.jayway.springmock;

import org.mockito.Mockito;
import org.springframework.beans.factory.FactoryBean;

/**
 * A {@link FactoryBean} for creating mocked beans based on Mockito so that they 
 * can be {@link @Autowired} into Spring test configurations.
 *
 * @author Mattias Severson, Jayway
 *
 * @see FactoryBean
 * @see org.mockito.Mockito
 */
public class MockitoFactoryBean<T> implements FactoryBean<T> {

    private Class<T> classToBeMocked;

    /**
     * Creates a Mockito mock instance of the provided class.
     * @param classToBeMocked The class to be mocked.
     */
    public MockitoFactoryBean(Class<T> classToBeMocked) {
        this.classToBeMocked = classToBeMocked;
    }

    @Override
    public T getObject() throws Exception {
        return Mockito.mock(classToBeMocked);
    }

    @Override
    public Class<?> getObjectType() {
        return classToBeMocked;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

अगला अपने वसंत विन्यास को निम्नलिखित के साथ अपडेट करें:

<beans...>
    <context:component-scan base-package="com.jayway.example"/>

    <bean id="someDependencyMock" class="com.jayway.springmock.MockitoFactoryBean">
        <constructor-arg name="classToBeMocked" value="com.jayway.example.SomeDependency" />
    </bean>
</beans>

2

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

सिर्फ सादे स्प्रिंग फीचर्स के साथ नकली बीन का विकल्प है। आपको इसके लिए उपयोग @Primary, @Profileऔर @ActiveProfilesएनोटेशन की आवश्यकता है । मैंने इस विषय पर एक ब्लॉग पोस्ट लिखा।


1

मुझे मॉकफैक्ट्री बनाने के लिए टीबॉट के समान उत्तर मिला जो मोक्स प्रदान करता है। मैंने नकली कारखाने बनाने के लिए निम्न उदाहरण का उपयोग किया (चूंकि लिंक narkisr के लिए मृत हैं): http://hg.randompage.org/java/src/407e78aa08a0/projects/bookmarking/backpr/src/test/java/ org / randompage / बुकमार्क / बैकएंड / testUtils / MocksFactory.java

<bean id="someFacade" class="nl.package.test.MockFactory">
    <property name="type" value="nl.package.someFacade"/>
</bean>

इससे यह रोकने में भी मदद मिलती है कि स्प्रिंग नकली सेम से इंजेक्शन को हल करना चाहता है।


1
<bean id="mockDaoFactory" name="dao" class="com.package.test.MocksFactory">
    <property name="type" value="com.package.Dao" />
</bean>

यह ^ पूरी तरह से अच्छी तरह से काम करता है अगर XML फ़ाइल में पहले / जल्दी घोषित किया जाता है। मॉकिटो 1.9.0 / स्प्रिंग 3.0.5


1

मैं मार्कस टी द्वारा उत्तर में उपयोग किए गए दृष्टिकोण के संयोजन का उपयोग करता हूं और एक सरल सहायक कार्यान्वयन ImportBeanDefinitionRegistrarएक कस्टम एनोटेशन ( @MockedBeans) के लिए दिखता है जिसमें कोई निर्दिष्ट कर सकता है कि किस वर्ग का मजाक उड़ाया जाना है। मेरा मानना ​​है कि इस दृष्टिकोण का नतीजा निकाले गए बॉयलरप्लेट कोड में से कुछ के साथ संक्षिप्त इकाई परीक्षण में होता है।

यहां बताया गया है कि नमूना इकाई परीक्षण उस दृष्टिकोण के साथ कैसा दिखता है:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class)
public class ExampleServiceIntegrationTest {

    //our service under test, with mocked dependencies injected
    @Autowired
    ExampleService exampleService;

    //we can autowire mocked beans if we need to used them in tests
    @Autowired
    DependencyBeanA dependencyBeanA;

    @Test
    public void testSomeMethod() {
        ...
        exampleService.someMethod();
        ...
        verify(dependencyBeanA, times(1)).someDependencyMethod();
    }

    /**
     * Inner class configuration object for this test. Spring will read it thanks to
     * @ContextConfiguration(loader=AnnotationConfigContextLoader.class) annotation on the test class.
     */
    @Configuration
    @Import(TestAppConfig.class) //TestAppConfig may contain some common integration testing configuration
    @MockedBeans({DependencyBeanA.class, DependencyBeanB.class, AnotherDependency.class}) //Beans to be mocked
    static class ContextConfiguration {

        @Bean
        public ExampleService exampleService() {
            return new ExampleService(); //our service under test
        }
    }
}

ऐसा करने के लिए आपको दो सरल सहायक वर्गों को परिभाषित करने की आवश्यकता है - कस्टम एनोटेशन ( @MockedBeans) और एक कस्टम ImportBeanDefinitionRegistrarकार्यान्वयन। @MockedBeansएनोटेशन परिभाषा के साथ एनोटेट करने @Import(CustomImportBeanDefinitionRegistrar.class)की ImportBeanDefinitionRgistrarआवश्यकता है और यह registerBeanDefinitionsविधि में कॉन्फ़िगरेशन के लिए नकली बीन्स परिभाषाओं को जोड़ने की आवश्यकता है ।

यदि आप इस दृष्टिकोण को पसंद करते हैं, तो आप मेरे ब्लॉगपोस्ट पर नमूना कार्यान्वयन पा सकते हैं ।


1

मैंने Kresimir Nesek के प्रस्ताव के आधार पर एक समाधान विकसित किया। मैंने कोड को थोड़ा क्लीनर और मॉड्यूलर बनाने के लिए एक नया एनोटेशन @EnableMockedBean जोड़ा ।

@EnableMockedBean
@SpringBootApplication
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes=MockedBeanTest.class)
public class MockedBeanTest {

    @MockedBean
    private HelloWorldService helloWorldService;

    @Autowired
    private MiddleComponent middleComponent;

    @Test
    public void helloWorldIsCalledOnlyOnce() {

        middleComponent.getHelloMessage();

        // THEN HelloWorldService is called only once
        verify(helloWorldService, times(1)).getHelloMessage();
    }

}

मैंने इसे समझाते हुए एक पोस्ट लिखी है ।


1

मैं आपकी परियोजना को स्प्रिंग बूट 1.4 में स्थानांतरित करने का सुझाव दूंगा। उसके बाद आप @MockBeanअपने एनोटेशन के लिए नए एनोटेशन का उपयोग कर सकते हैंcom.package.Dao


0

आज मुझे पता चला कि एक स्प्रिंग संदर्भ जहां मैंने मॉकिटो बीन्स से पहले घोषित किया था, लोड करने में विफल रहा था। बाद में मॉक को स्थानांतरित करने के बाद, एप्लिकेशन संदर्भ सफलतापूर्वक लोड किया गया था। ख्याल रखना :)


1
कुछ छूट रहा है। -) आप मोक्स के बाद क्या चले गए?
हंस-पीटर स्टॉर

0

रिकॉर्ड के लिए, मेरे सभी परीक्षण सही तरीके से काम करके केवल स्थिरता को आलसी-आरंभीकृत करते हैं, उदाहरण के लिए:

<bean id="fixture"
      class="it.tidalwave.northernwind.rca.embeddedserver.impl.DefaultEmbeddedServer"
      lazy-init="true" /> <!-- To solve Mockito + Spring problems -->

<bean class="it.tidalwave.messagebus.aspect.spring.MessageBusAdapterFactory" />

<bean id="applicationMessageBus"
      class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="it.tidalwave.messagebus.MessageBus" />
</bean>

<bean class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="javax.servlet.ServletContext" />
</bean>

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


-1

यदि आप नियंत्रक इंजेक्शन का उपयोग करते हैं, तो सुनिश्चित करें कि आपके स्थानीय चर "अंतिम" नहीं हैं

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.