2012-08-09 13 views
26

का उपयोग कर जावा में नई तिथि() का नकल कैसे करें मेरे पास एक ऐसा फ़ंक्शन है जो कुछ गणना करने के लिए वर्तमान समय का उपयोग करता है। मैं इसे मॉकिटो का उपयोग करके नकली करना चाहता हूं।मॉकिटो

वर्ग का एक उदाहरण मैं परीक्षण करना चाहते हैं:

@Test 
public void testDoubleTime(){ 
    mockDateSomeHow(Date.class).when(getTime()).return(30); 
    assertEquals(60,new ClassToTest().getDoubleTime()); 
} 

यह है कि नकली करना संभव है:

public class ClassToTest { 
    public long getDoubleTime(){ 
     return new Date().getTime()*2; 
    } 
} 

मैं की तरह कुछ करना चाहते हैं? मैं परीक्षण के लिए "परीक्षण" कोड को बदलना नहीं चाहूंगा।

+3

आप परीक्षण कोड क्यों नहीं बदलेंगे? कोड जो अधिक टेस्टेबल है आमतौर पर अधिक ढीला युग्मित होता है ... आप उसे क्यों नहीं चाहेंगे? – blank

+0

[जावा सिस्टम.currentTimeMillis ओवरराइड] के संभावित डुप्लिकेट (http://stackoverflow.com/questions/2001671/override-java-system-currenttimemillis) –

+0

... और दूसरी बात - 'परीक्षण' कोड बदलना आसान है - आप ' जब आपको गलती हुई तो आपको यह बताने के लिए परीक्षण मिल गए - दूसरी तरफ अन-परीक्षण कोड बदल रहा है ... आपको माइकल फेदर्स कुंग फू की आवश्यकता है;) – blank

उत्तर

39

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

interface DateTime { 
    Date getDate(); 
} 

class DateTimeImpl implements DateTime { 
    @Override 
    public Date getDate() { 
     return new Date(); 
    } 
} 

class MyClass { 

    private final DateTime dateTime; 
    // inject your Mock DateTime when testing other wise inject DateTimeImpl 

    public MyClass(final DateTime dateTime) { 
     this.dateTime = dateTime; 
    } 

    public long getDoubleTime(){ 
     return dateTime.getDate().getTime()*2; 
    } 
} 

public class MyClassTest { 
    private MyClass myClassTest; 

    @Before 
    public void setUp() { 
     final Date date = Mockito.mock(Date.class); 
     Mockito.when(date.getTime()).thenReturn(30L); 

     final DateTime dt = Mockito.mock(DateTime.class); 
     Mockito.when(dt.getDate()).thenReturn(date); 

     myClassTest = new MyClass(dt); 
    } 

    @Test 
    public void someTest() { 
     final long doubleTime = myClassTest.getDoubleTime(); 
     assertEquals(60, doubleTime); 
    } 
} 
+1

मैं सहमत हूं। मैं इसे हर समय ऐसा करता हूं। बहुत अच्छा काम करता है, मूल कोड में परिवर्तन न्यूनतम है और परीक्षण करना आसान है। – stmax

+12

यह समस्या हल करने का क्लासिक तरीका है (जिसे आप 'डेटटाइम' कहते हैं, अधिक वर्णनात्मक रूप से 'क्लॉक' या ऐसा कुछ कहा जा सकता है)। हालांकि, इसका मतलब है कि आपके कोड को पुनर्गठन करना और परीक्षण की अनुमति देने के लिए पूरी तरह जटिलता जोड़ना, जो कोड गंध का थोड़ा सा है। –

+0

तो मैंने किया, मुझे लगता है कि यह एक अच्छा अपमान है, लेकिन सवाल यह था कि इसे मॉकिटो के साथ कैसे किया जाए: डी –

6

आप PowerMock, जो Mockito बढाती है का उपयोग कर उपहास करने के लिए सक्षम होने के लिए कर ऐसा कर सकता है स्थैतिक तरीकों। आप mock System.currentTimeMillis() कर सकते हैं, जहां new Date() अंततः समय प्राप्त करता है।

आप कर सकते थे। मैं पर एक राय अग्रिम नहीं कर रहा हूं।

+1

का उपयोग करें मुझे यह जानने में दिलचस्पी है कि ऐसी चीजें कैसे करें, यह सवाल का उद्देश्य है। क्या आपके पास उदाहरण हैं? –

+0

यह [Powermock दस्तावेज] (http://code.google.com/p/powermock/wiki/MockSystem) से है। PowerMockito – Brad

+1

के साथ काम करना चाहिए, प्रत्येक "नया" को एक रैपर ऑब्जेक्ट में घुमाएं और इंजेक्शन निर्भरता के माध्यम से एक संकेत स्थापित करना केवल कोड को अनिवार्य रूप से वर्बोज़ और हार्ड बनाता है। यदि आप अपनी कक्षा के अंदर एक ऐरेलिस्ट या हैश मैप बना रहे थे, तो अब आप एक ऐरेलिस्ट फैक्ट्री या हैश मैपफैक्टरी बनायेंगे और इसे अपनी कक्षा में इंजेक्ट करेंगे? जब भी आप "नया" का उपयोग करते हैं तो PowerMock का उपयोग करके अंधेरे से एक बहुत कसकर युग्मित प्रणाली भी बना सकते हैं। यह बताने में सक्षम होने के नाते कि PowerMock जैसे उपकरण एक अच्छे फिट हैं, एक कुशल डेवलपर होने का हिस्सा हैं – Aneesh

14

आप विरासत कोड है, तो यह है कि आप refactor नहीं है और आप System.currentTimeMillis() प्रभावित करने के लिए नहीं करना चाहते हैं, इस Powermock और PowerMockito

//note the static import 
import static org.powermock.api.mockito.PowerMockito.whenNew; 

@PrepareForTest({ LegacyClassA.class, LegacyClassB.class }) 

@Before 
public void setUp() throws Exception { 

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 
    sdf.setTimeZone(TimeZone.getTimeZone("PST")); 

    Date NOW = sdf.parse("2015-05-23 00:00:00"); 

    // everytime we call new Date() inside a method of any class 
    // declared in @PrepareForTest we will get the NOW instance 
    whenNew(Date.class).withNoArguments().thenReturn(NOW); 

} 

public class LegacyClassA { 
    public Date getSomeDate() { 
    return new Date(); //returns NOW 
    } 
} 
1

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

तो

public class ClassToTest { 

    public long getDoubleTime() { 
     return getDoubleTime(new Date()); 
    } 

    long getDoubleTime(Date date) { // package visibility for tests 
     return date.getTime() * 2; 
    } 
} 

उत्पादन कोड में की तरह, आप getDoubleTime() और getDoubleTime(Date date) के खिलाफ परीक्षण का उपयोग करें।