2012-08-09 3 views
26

를 사용하여 자바의 새로운 날짜()을 조롱하는 방법. mockito를 사용하여 조롱하고 싶습니다.좀 계산을 위해 현재 시간을 사용하는 기능이 Mockito

클래스의 예 I 테스트 싶습니다

@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

가능한 중복 [재정의 자바에 System.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

이 문제를 해결하는 고전적인 방법입니다 ('DateTime '이라고 부르는 것을 좀 더 기술적으로'Clock '또는 이와 비슷한 것으로 부름). 그러나 이는 코드를 재구성하고 테스트를 허용하기 위해 약간의 복잡성을 추가하는 것을 의미합니다. 이는 약간의 코드 냄새입니다. –

+0

내가 한 것처럼, 좋은 aproach라고 생각하지만, 질문은 Mockito와 함께하는 방법이었습니다. D –

6

당신 은 조롱 할 수 Mockito을 증대 PowerMock를 사용하여이 작업을 수행 할 수 정적 메소드. 그런 다음 mock System.currentTimeMillis() 일 수 있으며, 이는 new Date()에서 최종 도착 시간입니다.

당신 . 이되어야하는지에 대한 의견을 제시하지 않겠습니다.

+1

나는 이런 일을하는 방법을 알고 싶어합니다. 그 질문의 목적입니다. 예가 있습니까? –

+0

이것은 [Powermock 문서] (http://code.google.com/p/powermock/wiki/MockSystem)에서 발췌 한 것입니다. PowerMockito와 동일하게 작동해야합니다. – Brad

+1

모든 "new"를 맹목적으로 래퍼 객체로 변환하고 삽입 된 종속성을 통해 간접 참조를 도입하면 코드가 불필요하게 길고 복잡해집니다. 클래스 내에서 ArrayList 또는 HashMap을 작성한다면 ArrayListFactory 또는 HashMapFactory를 작성하여이를 클래스에 삽입 할 수 있습니까? Blindly 당신이 "새로운"을 사용하는 곳곳에서 PowerMock을 사용하면 매우 밀접하게 결합 된 시스템을 만들 수 있습니다. PowerMock과 같은 도구가 숙련 된 개발자가되는 데 적합하다는 것을 알 수 있습니다. – Aneesh

14

당신이 리팩토링 수없고 System.currentTimeMillis()에 영향을하지 않는 레거시 코드가있는 경우, 직접 질문에 대답하지 않는 PowermockPowerMockito

//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(Date date)에 대한 getDoubleTime() 및 테스트를 사용합니다.

관련 문제