मैं मॉकिटो के साथ स्प्रिंग में एक स्वत: संचालित @Value क्षेत्र का मजाक कैसे करूं?


124

मैं स्प्रिंग 3.1.4 का उपयोग कर रहा हूं। कृपया और मॉकिटो 1.9.5। मेरे वसंत वर्ग में मेरे पास है:

@Value("#{myProps['default.url']}")
private String defaultUrl;

@Value("#{myProps['default.password']}")
private String defaultrPassword;

// ...

मेरे JUnit परीक्षण से, जिसे मैंने वर्तमान में सेट किया है:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:test-context.xml" })
public class MyTest 
{ 

मैं अपने "defaultUrl" फ़ील्ड के लिए एक मूल्य का मजाक बनाना चाहूंगा। ध्यान दें कि मैं अन्य क्षेत्रों के लिए मूल्यों का मजाक नहीं करना चाहता हूं - मैं उन्हें वैसे ही रखना चाहूंगा जैसे कि केवल "डिफॉल्टयूआरएल" क्षेत्र। यह भी ध्यान दें कि setDefaultUrlमेरी कक्षा में कोई स्पष्ट "सेटर" विधियाँ (जैसे ) नहीं हैं और मैं परीक्षण के प्रयोजनों के लिए कोई भी निर्माण नहीं करना चाहता।

इसे देखते हुए, मैं उस एक क्षेत्र के लिए एक मूल्य का कैसे मजाक उड़ा सकता हूं?

जवाबों:


145

आप ReflectionTestUtils.setFieldअपने कोड में किसी भी संशोधन करने से बचने के लिए स्प्रिंग के जादू का उपयोग कर सकते हैं ।

की जाँच करें इस और भी अधिक जानकारी के लिए ट्यूटोरियल, क्योंकि विधि उपयोग करना बहुत आसान है, हालांकि आप शायद इसकी आवश्यकता नहीं होगी

अपडेट करें

स्प्रिंग 4.2.RC1 की शुरुआत के बाद से अब कक्षा के एक उदाहरण की आपूर्ति किए बिना एक स्थिर क्षेत्र स्थापित करना संभव है। प्रलेखन के इस भाग को देखें और यह प्रतिबद्ध है।


12
बस लिंक मृत होने के मामले में: परीक्षण के दौरान ReflectionTestUtils.setField(bean, "fieldName", "value");अपनी beanविधि को लागू करने से पहले उपयोग करें ।
मिचेल स्टोकमल

2
गुण फ़ाइल से पुनर्प्राप्त करने वाले गुणों का मज़ाक करने के लिए अच्छा समाधान।
एंटनी संपत कुमार रेड्डी

@ MichałStochmal, ऐसा करने के बाद से जो उत्पादन होगा वह निजी java.lang.IllegalStateException है: विधि का उपयोग नहीं कर सकता है: Class org.springframework.util.ReflectionUtils, com.kaleidofin.app.service.impl.impl.CVLKRKKiderider ""
org.springframework.util

113

अब यह तीसरी बार था जब मैंने अपने आप को इस एसओ पद पर पहुंचा दिया क्योंकि मैं हमेशा भूल जाता हूं कि कैसे @Value फ़ील्ड का मज़ाक उड़ाया जाए। यद्यपि स्वीकृत उत्तर सही है, मुझे हमेशा "सेटफिल्ड" कॉल सही पाने के लिए कुछ समय की आवश्यकता होती है, इसलिए कम से कम खुद के लिए मैं यहां एक उदाहरण स्निपेट पेस्ट करता हूं:

उत्पादन वर्ग:

@Value("#{myProps[‘some.default.url']}")
private String defaultUrl;

टेस्ट क्लास:

import org.springframework.test.util.ReflectionTestUtils;

ReflectionTestUtils.setField(instanceUnderTest, "defaultUrl", "http://foo");
// Note: Don't use MyClassUnderTest.class, use the instance you are testing itself
// Note: Don't use the referenced string "#{myProps[‘some.default.url']}", 
//       but simply the FIELDs name ("defaultUrl")

32

आप अपनी संपत्ति कॉन्फ़िगरेशन को अपने परीक्षण वर्ग में भी मॉक कर सकते हैं

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:test-context.xml" })
public class MyTest 
{ 
   @Configuration
   public static class MockConfig{
       @Bean
       public Properties myProps(){
             Properties properties = new Properties();
             properties.setProperty("default.url", "myUrl");
             properties.setProperty("property.value2", "value2");
             return properties;
        }
   }
   @Value("#{myProps['default.url']}")
   private String defaultUrl;

   @Test
   public void testValue(){
       Assert.assertEquals("myUrl", defaultUrl);
   }
}

25

मैं एक संबंधित समाधान सुझाना चाहता हूं, जो कक्षा @Valueका उपयोग करने के बजाय, निर्माण के मापदंडों के रूप में -नोटेड खेतों को पारित करना है ReflectionTestUtils

इसके अलावा:

public class Foo {

    @Value("${foo}")
    private String foo;
}

तथा

public class FooTest {

    @InjectMocks
    private Foo foo;

    @Before
    public void setUp() {
        ReflectionTestUtils.setField(Foo.class, "foo", "foo");
    }

    @Test
    public void testFoo() {
        // stuff
    }
}

यह करो:

public class Foo {

    private String foo;

    public Foo(@Value("${foo}") String foo) {
        this.foo = foo;
    }
}

तथा

public class FooTest {

    private Foo foo;

    @Before
    public void setUp() {
        foo = new Foo("foo");
    }

    @Test
    public void testFoo() {
        // stuff
    }
}

इस दृष्टिकोण के लाभ: 1) हम एक निर्भरता कंटेनर के बिना फू वर्ग को रोक सकते हैं (यह सिर्फ एक निर्माता है), और 2) हम अपने परीक्षण को हमारे कार्यान्वयन विवरणों में युग्मित नहीं कर रहे हैं (प्रतिबिंब हमें एक स्ट्रिंग का उपयोग करके फ़ील्ड नाम से जोड़ता है, यदि हम क्षेत्र का नाम बदलते हैं तो समस्या पैदा हो सकती है)।


3
डाउनसाइड: यदि कोई एनोटेशन के साथ गड़बड़ करता है, उदाहरण के लिए 'फू' के बजाय एक प्रॉपर्टी 'बार' का उपयोग करता है, तो आपका परीक्षण अभी भी काम करेगा। मेरा बस यही मामला है।
नेल्स अल-हिमौड

@ NilsEl-Himoud ओपी प्रश्न के लिए सामान्य रूप से यह एक उचित बिंदु है, लेकिन आपके द्वारा उठाया गया मुद्दा प्रतिबिंब निर्माण बनाम निर्माणकर्ता का उपयोग करने से बेहतर या बुरा नहीं है। इस उत्तर का बिंदु प्रतिबिंब उपयोग (स्वीकृत उत्तर) से अधिक निर्माणकर्ता का विचार था। मार्क, जवाब के लिए धन्यवाद, मैं इस ट्वीक की सहजता और सफाई की सराहना करता हूं।
मार्की

22

आप इस मैजिक स्प्रिंग टेस्ट एनोटेशन का उपयोग कर सकते हैं:

@TestPropertySource(properties = { "my.spring.property=20" }) 

org.springframework.test.context.TestPropertySource देखें

उदाहरण के लिए, यह परीक्षण वर्ग है:

@ContextConfiguration(classes = { MyTestClass.Config.class })
@TestPropertySource(properties = { "my.spring.property=20" })
public class MyTestClass {

  public static class Config {
    @Bean
    MyClass getMyClass() {
      return new MyClass ();
    }
  }

  @Resource
  private MyClass myClass ;

  @Test
  public void myTest() {
   ...

और यह संपत्ति के साथ वर्ग है:

@Component
public class MyClass {

  @Value("${my.spring.property}")
  private int mySpringProperty;
   ...

13

मैंने नीचे दिए गए कोड का उपयोग किया और यह मेरे लिए काम आया:

@InjectMocks
private ClassABC classABC;

@Before
public void setUp() {
    ReflectionTestUtils.setField(classABC, "constantFromConfigFile", 3);
}

संदर्भ: https://www.jeejava.com/mock-an-autowired-value-field-in-spring-with-junit-mockito/


1
यहां वही ... + 1
कोमल

मैंने ऐसा ही किया, लेकिन फिर भी यह प्रतिबिंबित नहीं हुआ
शुभ्रो मुखर्जी

1

यह भी ध्यान दें कि मेरी कक्षा में कोई स्पष्ट "सेटर" विधियाँ नहीं हैं (उदाहरण के लिए setDefaultUrl) और मैं परीक्षण के प्रयोजनों के लिए कोई भी निर्माण नहीं करना चाहता।

इसे हल करने का एक तरीका कन्स्ट्रक्टर इंजेक्शन का उपयोग करने के लिए आपकी कक्षा को बदलना है , जिसका उपयोग परीक्षण और स्प्रिंग इंजेक्शन के लिए किया जाता है। कोई और प्रतिबिंब नहीं :)

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

class MySpringClass {

    private final String defaultUrl;
    private final String defaultrPassword;

    public MySpringClass (
         @Value("#{myProps['default.url']}") String defaultUrl, 
         @Value("#{myProps['default.password']}") String defaultrPassword) {
        this.defaultUrl = defaultUrl;
        this.defaultrPassword= defaultrPassword;
    }

}

और आपके परीक्षण में, बस इसका उपयोग करें:

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