2012-02-23 8 views
8

현재 날짜에 따라 DB에서 가져온 데이터에 다른 논리를 구현하는 방법이 있습니다.단위 테스트 Java의 시간 기반 논리

단위 테스트에서 개체를 만들어서 DB에 저장하고 테스트 된 메서드를 호출하도록 테스트하고 싶습니다. 그러나 예측 가능한 결과를 얻으려면 매번 시스템 날짜를 변경해야하며 Java에서이를 수행하는 방법을 알지 못합니다.

제안 사항?

+2

실제로 매개 변수로 시간을 제공하도록 메서드를 변경하면 원하는 시간을 지정하여 테스트 할 수 있습니다. 이것을 다시 말하는 것은 무엇입니까? – belgther

+0

현재 날짜와 시간은 어떻게 받고 있습니까? 어쩌면 조롱은 작동 할 것입니다 ... –

+0

지금은'new Date()'와 마찬가지로, 아마도 TimeProvider 클래스가 필요합니다. – Alex

답변

14

현재 날짜를 사용하여 예상 결과를 생성 할 수 있습니다.

또는 시계를 사용하지 않고 테스트 한 시간을 사용하도록 시스템을 작성하십시오. 그러면 시간은 항상 예상되는 시간입니다.

I는 I 데이터는 예를 들어 구동 될 수 FixedTimeSource를 사용하여 테스트에서

interface TimeSource { 
    long currentTimeMS(); // actually I have currentTimeNS 
    void currentTimeMS(long currentTimeMS); 
} 

enum VanillaTimeSource implements TimeSource { 
    INSTANCE; 

    @Override 
    public long currentTimeMS() { 
     return System.currentTimeMillis(); 
    } 

    @Override 
    public void currentTimeMS(long currentTimeMS) { 
     // ignored 
    } 
} 

class FixedTimeSource implements TimeSource { 
    private long currentTimeMS; 
    @Override 
    public long currentTimeMS() { 
     return currentTimeMS; 
    } 

    @Override 
    public void currentTimeMS(long currentTimeMS) { 
     this.currentTimeMS =    currentTimeMS; 
    } 
} 

같은 것을 사용 입력/이벤트에 의해 설정됩니다. 프로덕션에서는 입력/이벤트의 시간을 무시하고 현재 시간을 사용하는 VanillaTimeSource.INSTANCE를 사용합니다.

+0

첫 제안은 아마 이겼습니다. 일하지 마라. 또한 정확한 데이터를 가져 오는 것은 날짜를 기준으로 한 것입니다 (특정 열에 따라 다름). 이것은 논리가 다르지 않더라도 연중 거의 매일 다른 결과를 만들어야한다는 것을 의미합니다.아마도 두 번째 제안을 위해 갈 것입니다. – Alex

+0

결과를 확인하기 전에 테스트 실행의 일부로 예상 결과를 생성 할 수 있습니다. 미리 생성 할 필요는 없습니다. –

+0

실제로 시간을 매개 변수로받는 클래스/구성 요소를 만들면 시스템 시간과 분리되기 때문에 좋은 구성 요소임을 보장합니다. 모든 응용 프로그램 특정 구성 ("시스템 시간 사용")을 구성 요소 외부에 배치합니다. 외부 구성 가능한 자극에만 의존해야합니다. – helios

8

시간이 표시되는 방식을 사용자 정의 할 수 있도록 수업에 뭔가를 주입해야합니다.

예를

단위 테스트에서 지금
public interface TimeProvider { 
    DateTime getCurrentTime(); 
} 

public class UnderTest { 

    // Inject this in some way (e.g. provide it in the constructor) 
    private TimeProvider timeProvider; 

    public void MyMethod() { 
    if (timeProvider.getCurrentTime() == "1234") { 
     // Do something 
    } 
    } 
} 

위해 당신은 시간 제공자의 가짜 구현을 제공 할 수 있습니다. 실제 프로덕션 코드에서는 현재 날짜 시간 만 반환 할 수 있습니다.

+0

물론, 'belgther'가 제안하는 것처럼 매개 변수로 제공 할 수도 있습니다 : –

2

나는 최근에 너무 많은 리팩터링을 할 수 없었던 비슷한 문제가 있었다. (시간 제약, 실수로 무언가를 부러 뜨리고 싶지 않았다.) 그것은 System.currentTimeMillis()를 호출 한 테스트 메소드를 가지고 있었고 테스트하려는 경우는 그 값이 리턴 한 값에 달려있었습니다. 같은 :

public class ClassINeedToTest { 
    public boolean doStuff() { 
     long l = System.currentTimeMillis(); 
     // do some calculation based on l 
     // and return the calculation 
    } 
} 

는 단위 테스트를 허용하려면, 나는()는

protected long getCurrentTimeMillis() { 
    // only for unit-testing purposes 
    return System.currentTimeMillis(); 
} 

보호 된 도우미 메서드를 가지고 있도록 클래스를 리팩토링이 방법은 doStuff에 의해 호출되었다. 이 기능을 변경하지만 지금은 단위 테스트를 호출 할 때, 그때 그러나 나는를 오염 한 것을 의미합니까

ClassINeedToTest testClass = new ClassINeedToTest() { 
    protected long getCurrentTimeMillis() { 
     // return specific date for my test 
     return 12456778L; 
    } 
}; 
boolean result = testClass.doStuff(); 
// test result with an assert here 

이를 같이 특정 값을 반환하는이 메소드를 오버라이드 (override) 할 수 있다는 것을 의미하지 않았다 인터페이스를 사용하여 비용이 너무 높다고 결정할 수 있습니다. 코드를 더 리팩토링 할 수 있다면 더 좋은 방법이있을 것입니다.