प्रारंभिक नकली वस्तुएं - MockIto


122

MockIto का उपयोग करके एक मॉक ऑब्जेक्ट को इनिशियलाइज़ करने के कई तरीके हैं। इनमें से सबसे अच्छा तरीका क्या है?

1।

 public class SampleBaseTestCase {

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

2।

@RunWith(MockitoJUnitRunner.class)

[संपादित करें] ३।

mock(XXX.class);

मुझे सुझाव दें कि क्या इनसे बेहतर कोई और तरीका है ...

जवाबों:


153

मोक्स इनिशियलाइज़ेशन के लिए , रनर का उपयोग कर रहे हैं या MockitoAnnotations.initMocksकड़ाई से समकक्ष समाधान हैं। MockitoJUnitRunner के javadoc से :

JUnit 4.5 runner initializes mocks annotated with Mock, so that explicit usage of MockitoAnnotations.initMocks(Object) is not necessary. Mocks are initialized before each test method.


MockitoAnnotations.initMocksजब आप पहले से ही एक विशिष्ट धावक ( SpringJUnit4ClassRunnerउदाहरण के लिए) को अपने परीक्षण के मामले में कॉन्फ़िगर कर चुके हैं, तो पहले समाधान (के साथ ) का उपयोग किया जा सकता है ।

दूसरा समाधान (के साथ MockitoJUnitRunner) अधिक क्लासिक और मेरा पसंदीदा है। कोड सरल है। रनर का उपयोग करने से फ्रेमवर्क उपयोग के स्वत: सत्यापन का शानदार लाभ मिलता है ( इस उत्तर में @ डेविड वैलेस द्वारा वर्णित )।

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

@RunWith(MockitoJUnitRunner.class)
public class ArticleManagerTest {

    @Mock private ArticleCalculator calculator;
    @Mock(name = "database") private ArticleDatabase dbMock;
    @Spy private UserProvider userProvider = new ConsumerUserProvider();

    @InjectMocks private ArticleManager manager;

    @Test public void shouldDoSomething() {
        manager.initiateArticle();
        verify(database).addListener(any(ArticleListener.class));
    }

    @Test public void shouldDoSomethingElse() {
        manager.finishArticle();
        verify(database).removeListener(any(ArticleListener.class));
    }
}

पेशेवरों: कोड न्यूनतम है

विपक्ष: काला जादू। IMO यह मुख्य रूप से @InjectMocks एनोटेशन के कारण है। इस एनोटेशन के साथ "आप कोड के दर्द को ढीला करते हैं" ( @Brice की शानदार टिप्पणियाँ देखें )


तीसरा उपाय यह है कि प्रत्येक परीक्षा पद्धति पर अपना मॉक बनाएं। यह अपने जवाब में " एमएलके द्वारा " आत्म निहित परीक्षण करने के लिए समझाया गया है ।

public class ArticleManagerTest {

    @Test public void shouldDoSomething() {
        // given
        ArticleCalculator calculator = mock(ArticleCalculator.class);
        ArticleDatabase database = mock(ArticleDatabase.class);
        UserProvider userProvider = spy(new ConsumerUserProvider());
        ArticleManager manager = new ArticleManager(calculator, 
                                                    userProvider, 
                                                    database);

        // when 
        manager.initiateArticle();

        // then 
        verify(database).addListener(any(ArticleListener.class));
    }

    @Test public void shouldDoSomethingElse() {
        // given
        ArticleCalculator calculator = mock(ArticleCalculator.class);
        ArticleDatabase database = mock(ArticleDatabase.class);
        UserProvider userProvider = spy(new ConsumerUserProvider());
        ArticleManager manager = new ArticleManager(calculator, 
                                                    userProvider, 
                                                    database);

        // when 
        manager.finishArticle();

        // then
        verify(database).removeListener(any(ArticleListener.class));
    }
}

पेशेवरों: आप स्पष्ट रूप से प्रदर्शित करते हैं कि आपके एपीआई कैसे काम करते हैं (बीडीडी ...)

विपक्ष: अधिक बॉयलरप्लेट कोड है। (मोक्स क्रिएशन)


मेरी सिफारिश एक समझौता है। के @Mockसाथ एनोटेशन का उपयोग करें @RunWith(MockitoJUnitRunner.class), लेकिन इसका उपयोग न करें @InjectMocks:

@RunWith(MockitoJUnitRunner.class)
public class ArticleManagerTest {

    @Mock private ArticleCalculator calculator;
    @Mock private ArticleDatabase database;
    @Spy private UserProvider userProvider = new ConsumerUserProvider();

    @Test public void shouldDoSomething() {
        // given
        ArticleManager manager = new ArticleManager(calculator, 
                                                    userProvider, 
                                                    database);

        // when 
        manager.initiateArticle();

        // then 
        verify(database).addListener(any(ArticleListener.class));
    }

    @Test public void shouldDoSomethingElse() {
        // given
        ArticleManager manager = new ArticleManager(calculator, 
                                                    userProvider, 
                                                    database);

        // when 
        manager.finishArticle();

        // then 
        verify(database).removeListener(any(ArticleListener.class));
    }
}

पेशेवरों: आप स्पष्ट रूप से प्रदर्शित करते हैं कि आपकी एपीआई कैसे काम करती है (कैसे मेरी ArticleManagerतत्काल है)। कोई बॉयलरप्लेट कोड नहीं।

विपक्ष: परीक्षण आत्म निहित नहीं है, कोड का कम दर्द


हालांकि सावधान रहें, एनोटेशन उपयोगी हैं, लेकिन वे आपको खराब ओओ डिजाइन (या इसे नीचा दिखाने) के लिए शिल्प की रक्षा नहीं करते हैं। व्यक्तिगत रूप से जब मैं बॉयलरप्लेट कोड को कम करने के लिए खुश हूं, तो मैं कोड (या पीआईटीए) के दर्द को ढीला कर देता हूं जो कि डिजाइन को बेहतर तरीके से बदलने के लिए ट्रिगर है, इसलिए मैं और टीम ओओ डिजाइन पर ध्यान दे रहे हैं। मुझे लगता है कि SOLID डिजाइन या GOOS विचारों जैसे सिद्धांतों के साथ OO डिजाइन का पालन करना अधिक महत्वपूर्ण है, जो यह बताता है कि कैसे मोक्स को इंस्टेंट करना है।
ब्राइस

1
(अनुवर्ती) यदि आप यह नहीं देखते हैं कि यह वस्तु कैसे बनाई गई है तो आप इसके बारे में दर्द महसूस नहीं करते हैं, और भविष्य के प्रोग्रामर अच्छी तरह से प्रतिक्रिया नहीं कर सकते हैं यदि नई कार्यक्षमता को जोड़ा जाना चाहिए। वैसे भी जो दोनों तरह से तर्कपूर्ण है, मैं सिर्फ इसके बारे में सावधान रहने के लिए कह रहा हूं।
ब्राइस

6
यह सही नहीं है कि ये दोनों बराबर हैं। यह सच नहीं है कि सरल कोड का उपयोग करने का एकमात्र फायदा है MockitoJUnitRunner। मतभेदों के बारे में अधिक जानकारी के लिए, stackoverflow.com/questions/10806345/… पर प्रश्न देखें और इसका उत्तर दें।
दाऊद इब्न करीम

2
@Gontard हाँ यकीन है कि निर्भरताएं दिखाई दे रही हैं, लेकिन मैंने देखा है कि इस दृष्टिकोण का उपयोग करके कोड गलत हो गया है। Collaborator collab = mock(Collaborator.class)मेरे विचार में, इस तरह से उपयोग करने के बारे में निश्चित रूप से एक वैध दृष्टिकोण है। हालांकि यह क्रिया हो सकती है, आप परीक्षणों की समझ और शोधन क्षमता में प्राप्त कर सकते हैं। दोनों तरीकों में उनके पेशेवरों और विपक्ष हैं, मैंने अभी तक तय नहीं किया है कि कौन सा दृष्टिकोण बेहतर है। एमीवे हमेशा बकवास लिखना संभव है, और शायद संदर्भ और कोडर पर निर्भर करता है।
ब्रिस

1
@mlk मैं आपसे पूरी तरह सहमत हूँ। मेरी अंग्रेजी बहुत अच्छी नहीं है और इसमें बारीकियों की कमी है। मेरी बात UNIT शब्द पर जोर देने की थी।
gontard

30

अब (v1.10.7 के रूप में) मॉक को तुरंत करने का चौथा तरीका है, जो मॉकिटो रूल नामक एक JUnit4 नियम का उपयोग कर रहा है ।

@RunWith(JUnit4.class)   // or a different runner of your choice
public class YourTest
  @Rule public MockitoRule rule = MockitoJUnit.rule();
  @Mock public YourMock yourMock;

  @Test public void yourTestMethod() { /* ... */ }
}

JUnit @Rule के साथ दिए गए TestRule के उपवर्गों की तलाश करता है, और उनका उपयोग वह परीक्षण विवरण लपेटने के लिए करता है जो Runner प्रदान करता है । इसका मुख्य कारण यह है कि आप @ विधि, @ विधि के बाद, और यहां तक ​​कि प्रयास कर सकते हैं ... रैपर को नियमों में पकड़ सकते हैं। तुम भी अपने परीक्षण के भीतर से इन के साथ बातचीत कर सकते हैं, जिस तरह से ExpectedException करता है।

MockitoRule लगभग बिल्कुल MockitoJUnitRunner की तरह व्यवहार करता है , सिवाय इसके कि आप किसी अन्य धावक का उपयोग कर सकते हैं, जैसे कि Parameterized (जो आपके परीक्षण निर्माणकर्ताओं को तर्क लेने की अनुमति देता है ताकि आपके परीक्षण कई बार चल सकें), या Robolectric का परीक्षण धावक (इसलिए इसका सहपाठी जावा प्रतिस्थापन प्रदान कर सकता है) एंड्रॉयड देशी कक्षाओं के लिए)। यह हाल ही में JUnit और मॉकिटो संस्करणों में उपयोग करने के लिए इसे और अधिक लचीला बनाता है।

संक्षेप में:

  • Mockito.mock(): बिना एनोटेशन समर्थन या उपयोग सत्यापन के साथ सीधे मंगलाचरण।
  • MockitoAnnotations.initMocks(this): एनोटेशन समर्थन, कोई उपयोग सत्यापन नहीं।
  • MockitoJUnitRunner: एनोटेशन समर्थन और उपयोग सत्यापन, लेकिन आपको उस धावक का उपयोग करना होगा।
  • MockitoRule: किसी भी JUnit धावक के साथ एनोटेशन समर्थन और उपयोग सत्यापन।

यह भी देखें: JUnit @Rule कैसे काम करता है?


3
कोटलिन में, नियम इस तरह दिखता है:@get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
क्रिस्चन

10

ऐसा करने का एक साफ तरीका है।

  • यदि यह एक यूनिट टेस्ट है तो आप ऐसा कर सकते हैं:

    @RunWith(MockitoJUnitRunner.class)
    public class MyUnitTest {
    
        @Mock
        private MyFirstMock myFirstMock;
    
        @Mock
        private MySecondMock mySecondMock;
    
        @Spy
        private MySpiedClass mySpiedClass = new MySpiedClass();
    
        // It's gonna inject the 2 mocks and the spied object per reflection to this object
        // The java doc of @InjectMocks explains it really well how and when it does the injection
        @InjectMocks
        private MyClassToTest myClassToTest;
    
        @Test
        public void testSomething() {
        }
    }
    
  • संपादित करें: यदि यह एक एकीकरण परीक्षण है, तो आप ऐसा कर सकते हैं (वसंत के साथ उस तरह का उपयोग करने का इरादा नहीं है। बस दिखावा करें कि आप अलग-अलग धावक के साथ मॉक को शुरू कर सकते हैं):

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("aplicationContext.xml")
    public class MyIntegrationTest {
    
        @Mock
        private MyFirstMock myFirstMock;
    
        @Mock
        private MySecondMock mySecondMock;
    
        @Spy
        private MySpiedClass mySpiedClass = new MySpiedClass();
    
        // It's gonna inject the 2 mocks and the spied object per reflection to this object
        // The java doc of @InjectMocks explains it really well how and when it does the injection
        @InjectMocks
        private MyClassToTest myClassToTest;
    
        @Before
        public void setUp() throws Exception {
              MockitoAnnotations.initMocks(this);
        }
    
        @Test
        public void testSomething() {
        }
    }
    

1
अगर M एकता एकीकरण परीक्षणों में भी शामिल है, तो क्या यह समझ में आएगा?
विनयवेलुरी

2
वास्तव में यह आपका अधिकार नहीं होगा। मैं सिर्फ मॉकिटो की संभावनाओं को दिखाना चाहता था। उदाहरण के लिए यदि आपका उपयोग RESTFuse है तो आपको उनके धावक को उपयोगकर्ता करना होगा ताकि आप MockitoAnnotations.initMocks (यह) के साथ मॉक को आरंभ कर सकें;
ईएमडी

8

MockitoAnnotations और धावक के ऊपर अच्छी तरह से चर्चा की गई है, इसलिए मैं अनलॉफ के लिए अपने tuppence में फेंकने जा रहा हूं:

XXX mockedXxx = mock(XXX.class);

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


क्या मॉक (XX.class) का उपयोग करने पर कोई अन्य लाभ होता है सिवाय परीक्षण के मामले को आत्म निहित करने के?
विनयवेलुरी

जहां तक ​​मेरी जानकारी नहीं है।
माइकल लॉयड ली mlk

3
टेस्ट पढ़ने के लिए समझने के लिए कम जादू। आप चर घोषित करते हैं, और इसे एक मूल्य देते हैं - कोई एनोटेशन, प्रतिबिंब आदि
कारू

2

JUnit 5 जुपिटर के लिए एक छोटा सा उदाहरण, "रनविथ" को हटा दिया गया था जिसे अब आपको "@ExtendWith" एनोटेशन का उपयोग करके एक्सटेंशन्स का उपयोग करने की आवश्यकता है।

@ExtendWith(MockitoExtension.class)
class FooTest {

  @InjectMocks
  ClassUnderTest test = new ClassUnderTest();

  @Spy
  SomeInject bla = new SomeInject();
}

0

अन्य उत्तर महान हैं और यदि आप उन्हें चाहते हैं / चाहते हैं तो अधिक विवरण शामिल हैं।
उन लोगों के अलावा, मैं एक TL जोड़ना चाहूंगा? DR:

  1. उपयोग करना पसंद करते हैं
    • @RunWith(MockitoJUnitRunner.class)
  2. यदि आप नहीं कर सकते हैं (क्योंकि आप पहले से ही एक अलग धावक का उपयोग करते हैं), का उपयोग करना पसंद करते हैं
    • @Rule public MockitoRule rule = MockitoJUnit.rule();
  3. (2) के समान, लेकिन आपको इसका उपयोग नहीं करना चाहिए :
    • @Before public void initMocks() { MockitoAnnotations.initMocks(this); }
  4. यदि आप केवल एक परीक्षण में एक नकली का उपयोग करना चाहते हैं और एक ही परीक्षण कक्षा में अन्य परीक्षणों के लिए इसे उजागर नहीं करना चाहते हैं, तो उपयोग करें
    • X x = mock(X.class)

(1) और (2) और (3) परस्पर अनन्य हैं।
(4) दूसरों के साथ संयोजन में इस्तेमाल किया जा सकता है।

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