2012-06-01 1 views
15

Ich benutze JodaTime 2.1 und ich suche nach einem Muster zu Unit-Test-Code, der Datum/Uhrzeit-Operationen durchführt, um sicherzustellen, dass es sich gut für alle Zeitzonen und unabhängig von DST verhält.Wie schreibe ich Komponententests, um sicherzustellen, dass mein Datum/Zeit-basierter Code für alle Zeitzonen und ohne Sommerzeit funktioniert?

Im Einzelnen:

  1. Wie kann ich die Systemuhr verspotten (so muss ich nicht alle Orte, verspotten, wo ich new DateTime() rufen Sie die aktuelle Zeit zu bekommen)
  2. Wie kann ich das gleiche tun für die Standardzeitzone?
+0

mögliche Duplikate von [Einheitentests mit Daten werden in allen Zeitzonen und mit/ohne Sommerzeit durchgeführt] (http://stackoverflow.com/questions/10833948/make-unit-tests-with-dates-pass-in- all-time-zones-and-with-out-dst) – Caleb

+0

Es ist kein Duplikat; Es ist ein Follow-up. –

Antwort

18

können Sie ein @Rule für diesen. Hier ist der Code für die Regel:

import org.joda.time.DateTimeZone; 
import org.junit.rules.TestWatcher; 
import org.junit.runner.Description; 

public class UTCRule extends TestWatcher { 

    private DateTimeZone origDefault = DateTimeZone.getDefault(); 

    @Override 
    protected void starting(Description description) { 
     DateTimeZone.setDefault(DateTimeZone.UTC); 
    } 

    @Override 
    protected void finished(Description description) { 
     DateTimeZone.setDefault(origDefault); 
    } 
} 

Sie die Regel wie diese verwenden:

public class SomeTest { 

    @Rule 
    public UTCRule utcRule = new UTCRule(); 

    .... 
} 

Dadurch wird die aktuelle Zeitzone UTC vor jedem Test in SomeTest ausgeführt wird ändern und es wird Stellen Sie die Standardzeitzone nach jedem Test wieder her.

Wenn Sie mehrere Zeitzonen zu überprüfen, verwenden Sie eine Regel wie diese:

import org.joda.time.DateTimeZone; 
import org.junit.rules.TestWatcher; 
import org.junit.runner.Description; 

public class TZRule extends TestWatcher { 

    private DateTimeZone origDefault = DateTimeZone.getDefault(); 

    private DateTimeZone tz; 

    public TZRule(DateTimeZone tz) { 
     this.tz = tz; 
    } 

    @Override 
    protected void starting(Description description) { 
     DateTimeZone.setDefault(tz); 
    } 

    @Override 
    protected void finished(Description description) { 
     DateTimeZone.setDefault(origDefault); 
    } 
} 

Legen Sie alle betroffenen Tests in einer abstrakten Basisklasse AbstractTZTest und erweitern sie:

public class UTCTest extends AbstractTZTest { 
    @Rule public TZRule tzRule = new TZRule(DateTimeZone.UTC); 
} 

That führt alle Tests in AbstractTZTest mit UTC aus. Für jede Zeitzone, die Sie testen möchten, müssen Sie eine andere Klasse benötigen:

public class UTCTest extends AbstractTZTest { 
    @Rule public TZRule tzRule = new TZRule(DateTimeZone.forID("..."); 
} 

Da Testfälle vererbt werden, das ist alles - Sie müssen nur die Regel definieren.

In ähnlicher Weise können Sie die Systemuhr verschieben. Verwenden Sie eine Regel, die DateTimeUtils.setCurrentMillisProvider(...) aufruft, um zu simulieren, dass der Test zu einer bestimmten Zeit ausgeführt wird, und DateTimeUtils.setCurrentMillisSystem(), um die Standardeinstellungen wiederherzustellen.

Hinweis: Ihr Provider muss eine Möglichkeit haben, die Uhr ankreuzen zu lassen oder alle neuen DateTime Instanzen haben denselben Wert. Ich erweitere den Wert oft um eine Millisekunde jedes Mal, wenn getMillis() aufgerufen wird.

Hinweis 2: Das funktioniert nur mit joda-Zeit. Es hat keinen Einfluss auf new java.util.Date().

2
for (String zoneId : DateTimeZone.getAvailableIDs()) 
{ 
    DateTime testedDate1; 
    DateTime testedDate2; 
    try 
    { 
     final DateTimeZone tz = DateTimeZone.forID(zoneId); 
     // your test with testedDate1 and testedDate2 
    } 
    catch (final IllegalArgumentException e) 
    { 
     // catching DST problem 
     testedDate1 = testetDate1.plusHours(1); 
     testedDate2 = testetDate2.plusHours(1); 
     // repeat your test for this dates 
    } 
} 

Änderung für einzelnen Test

DateTimeZone default; 

DateTimeZone testedTZ; 

@Before 
public void setUp() 
{ 
    default = GateTimeZone.getDefault(); 
    DateTimeZone.setDefault 
} 

@After 
public void tearDown() 
{ 
    default = GateTimeZone.setDefault(); 
    DateTimeZone.setDefault(testedTZ) 
} 

@Test 
public void test() 
{ 
//... 
} 
+0

Ich bin mir nicht sicher, ob dies unabhängig von der Sommerzeit funktioniert. Zum Beispiel bekomme ich gerade die Zeitzone für "USA/Pazifik". Und jetzt, da wir noch in der Sommerzeit sind, bekomme ich einen Offset von -25200 zurück. Aber wenn wir im November zur Standardzeit zurückkehren, wird derselbe Code -28800 zurückgeben. Täusche ich mich deswegen? – Marvo

Verwandte Themen