मॉकिटो स्थानीय रूप से अंतिम वर्ग का मजाक बनाता है लेकिन जेनकिंस में विफल रहता है


11

मैंने स्थैतिक विधि के लिए कुछ इकाई परीक्षण लिखे हैं। स्थैतिक विधि केवल एक तर्क लेती है। तर्क का प्रकार एक अंतिम वर्ग है। कोड के संदर्भ में:

public class Utility {

   public static Optional<String> getName(Customer customer) {
       // method's body.
   }
}

public final class Customer {
   // class definition
}

इसलिए Utilityकक्षा के लिए मैंने एक परीक्षण वर्ग बनाया है UtilityTestsजिसमें मैंने इस पद्धति के लिए परीक्षण लिखे हैं getName। यूनिट टेस्टिंग फ्रेमवर्क TestNG है और उपयोग की जाने वाली मॉकिंग लाइब्रेरी है Mockito। इसलिए एक विशिष्ट परीक्षण में निम्नलिखित संरचना होती है:

public class UtilityTests {

   @Test
   public void getNameTest() {
     // Arrange
     Customer customerMock = Mockito.mock(Customer.class);
     Mockito.when(...).thenReturn(...);

     // Act
     Optional<String> name = Utility.getName(customerMock);

     // Assert
     Assert.assertTrue(...);
   }
}

समस्या क्या है ?

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

org.mockito.exception.base.MockitoException: नकली / जासूसी वर्ग कोम नहीं कर सकते। com.packagename.Customer Mockito नकली / जासूसी नहीं कर सकता क्योंकि: - अंतिम वर्ग

मैंने क्या कोशिश की?

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

प्रशन

तो यहाँ दो प्रश्न हैं:

  1. यह पहली जगह में कैसे संभव है? परीक्षण स्थानीय और जेनकींस दोनों में विफल नहीं होना चाहिए?
  2. ऊपर बताई गई बाधाओं के आधार पर इसे कैसे तय किया जा सकता है?

किसी भी सहायता के लिए अग्रिम रूप से धन्यवाद।


1
मेरा अनुमान है कि enable finalकॉन्फ़िगरेशन आपके कार्यक्षेत्र में काम करता है, लेकिन जब Jenkinsइस फ़ाइल को खोजने में असमर्थ होने पर चलाया जाता है । जाँच करें Jenkinsकि फ़ाइल की तलाश कहाँ है और वास्तव में वहाँ है या नहीं।
दूसरा

यह अन्य सूत्र बताता है कि मॉकिटो 2 में अंतिम वर्ग मॉकिंग को कैसे सक्षम किया जाए, संसाधन निर्देशिका के तहत एक मॉकिटो कॉन्फ़िगरेशन फ़ाइल जोड़कर: stackoverflow.com/questions/14292863/…
जोस Tepedino

3
क्या यह संभव हो सकता है, जिस कोड के साथ आप काम कर रहे हैं, ग्राहक वर्ग से एक इंटरफ़ेस निकालने के लिए, ICustomer का कहना है, और उपयोगिता वर्ग में इसका उपयोग करें? तब आप उस इंटरफ़ेस को ठोस अंतिम वर्ग के बजाय मॉक कर सकते थे
जोस टेपेडिनो 25'19

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

1
क्या Customerइसमें कोई तर्क है, या यह सिर्फ एक गूंगा डेटा वर्ग है? अगर यह सिर्फ गेटर्स और सेटर के साथ खेतों का एक गुच्छा है, तो आप इसे तुरंत इंस्टाल कर सकते हैं।
विलिस ब्लैकबर्न

जवाबों:


2

एक वैकल्पिक तरीका होगा 'पद्धति टू क्लास' पैटर्न का उपयोग करना।

  1. ग्राहक वर्ग के तरीकों को किसी अन्य वर्ग / वर्गों में ले जाएँ, कहो CustomerSomething उदा / CustomerFinances (या जो कुछ भी यह जिम्मेदारी है)।
  2. ग्राहक के लिए एक निर्माता जोड़ें।
  3. अब आपको ग्राहक का मजाक उड़ाने की जरूरत नहीं है, सिर्फ ग्राहकसमर्थन वर्ग! आपको इसका मजाक उड़ाने की जरूरत नहीं है कि या तो इसकी कोई बाहरी निर्भरता नहीं है।

यहाँ इस विषय पर एक अच्छा ब्लॉग है: https://simpleprogrammer.com/back-to-basics-mock-eliminating-patterns/


1
आपके उत्तर के लिए धन्यवाद (+1)। मुझे इसे ठीक करने का एक तरीका मिला (दूसरे प्रश्न का उत्तर)। हालाँकि, इंटेलीज के अंदर परीक्षण विफल होने का कारण अभी भी मेरे लिए स्पष्ट नहीं है। इसके अलावा, मैं इसे अब (IntelliJ के अंदर की विफलता) को पुन: पेश नहीं कर सकता, जो पूरी तरह से अजीब है।
क्रिस्टोस

1

यह पहली जगह में कैसे संभव है? परीक्षण स्थानीय और जेनकींस दोनों में विफल नहीं होना चाहिए?

यह स्पष्ट रूप से एक प्रकार की एनवी-विशिष्टता है। एकमात्र सवाल है - अंतर के कारण को कैसे निर्धारित किया जाए।

मैं आपको org.mockito.internal.util.MockUtil#typeMockabilityOfविधि की जांच करने और तुलना करने का सुझाव दूंगा कि mockMakerवास्तव में पर्यावरण और क्यों दोनों में उपयोग किया जाता है।

यदि mockMakerसमान है - लोड की गई कक्षाओं IDE-Clientबनाम की तुलना करें Jenkins-Client- क्या उन्हें परीक्षण निष्पादन के समय कोई अंतर है।

ऊपर बताई गई बाधाओं के आधार पर इसे कैसे तय किया जा सकता है?

निम्न कोड OpenJDK 12 और मॉकिटो 2.28.2 की धारणा में लिखा गया है, लेकिन मेरा मानना ​​है कि आप इसे वास्तव में उपयोग किए गए संस्करण में समायोजित कर सकते हैं।

public class UtilityTest {    
    @Rule
    public InlineMocksRule inlineMocksRule = new InlineMocksRule();

    @Rule
    public MockitoRule mockitoRule = MockitoJUnit.rule();

    @Test
    public void testFinalClass() {
        // Given
        String testName = "Ainz Ooal Gown";
        Client client = Mockito.mock(Client.class);
        Mockito.when(client.getName()).thenReturn(testName);

        // When
        String name = Utility.getName(client).orElseThrow();

        // Then
        assertEquals(testName, name);
    }

    static final class Client {
        final String getName() {
            return "text";
        }
    }

    static final class Utility {
        static Optional<String> getName(Client client) {
            return Optional.ofNullable(client).map(Client::getName);
        }
    }    
}

इनलाइन मोक्स के लिए एक अलग नियम के साथ:

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.mockito.internal.configuration.plugins.Plugins;
import org.mockito.internal.util.MockUtil;

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class InlineMocksRule implements TestRule {
    private static Field MOCK_MAKER_FIELD;

    static {
        try {
            MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(Field.class, MethodHandles.lookup());
            VarHandle modifiers = lookup.findVarHandle(Field.class, "modifiers", int.class);

            MOCK_MAKER_FIELD = MockUtil.class.getDeclaredField("mockMaker");
            MOCK_MAKER_FIELD.setAccessible(true);

            int mods = MOCK_MAKER_FIELD.getModifiers();
            if (Modifier.isFinal(mods)) {
                modifiers.set(MOCK_MAKER_FIELD, mods & ~Modifier.FINAL);
            }
        } catch (IllegalAccessException | NoSuchFieldException ex) {
            throw new RuntimeException(ex);
        }
    }

    @Override
    public Statement apply(Statement base, Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                Object oldMaker = MOCK_MAKER_FIELD.get(null);
                MOCK_MAKER_FIELD.set(null, Plugins.getPlugins().getInlineMockMaker());
                try {
                    base.evaluate();
                } finally {
                    MOCK_MAKER_FIELD.set(null, oldMaker);
                }
            }
        };
    }
}

आपके उत्तर के लिए धन्यवाद (+1)। मुझे इसे ठीक करने का एक तरीका मिला (दूसरे प्रश्न का उत्तर)। हालाँकि, इंटेलीज के अंदर परीक्षण विफल होने का कारण अभी भी मेरे लिए स्पष्ट नहीं है। इसके अलावा, मैं इसे अब (IntelliJ के अंदर की विफलता) को पुन: पेश नहीं कर सकता, जो पूरी तरह से अजीब है।
क्रिस्टोस

1

सुनिश्चित करें कि आप परीक्षण को उसी तर्कों के साथ चलाते हैं। जांचें कि क्या आपके इंटेलीज रन कॉन्फ़िगरेशन जेनकिंस से मेल खाते हैं। https://www.jetbrains.com/help/idea/creating-and-editing-run-debug-configurations.html । आप स्थानीय मशीन पर जेंकिंस (टर्मिनल से) के समान तर्कों के साथ परीक्षण चलाने का प्रयास कर सकते हैं, यदि यह विफल हो जाएगा अर्थात तर्क में समस्या है


फ़ाइल org.mockito.plugins.MockMakerजेनकींस मशीन में भी मौजूद है। मैं बॉट मशीनों में उसी JVM का उपयोग करता हूं। मैं आपके द्वारा बताए गए 3 की जांच करूंगा। धन्यवाद
क्रिस्टोस

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

अपने रन कॉन्फ़िगरेशन में .idea / workspace.xml पर एक नज़र डालें, यह एक <घटक> टैग के अंदर है। उसके बाद आप सीख सकते हैं कि कैसे xml को bash कमांड में बदलना है
Link182

क्या आप जेनकिंस टर्मिनल कमांड दिखा सकते हैं जिसका उपयोग परीक्षण चलाने के लिए किया जाता है? आप यह भी बता सकते हैं कि आप किस पैकेज मैनेजर का उपयोग करते हैं?
लिंक 182

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