java - ¿Cómo escribo las pruebas unitarias para asegurarme de que mi código basado en fecha/hora funcione para todas las zonas horarias y sin/sin DST?
unit-testing timezone (2)
Puedes usar una @Rule
para esto. Aquí está el código para la regla:
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 );
}
}
Puedes usar la regla así:
public class SomeTest {
@Rule
public UTCRule utcRule = new UTCRule();
....
}
Esto cambiará la zona horaria actual a UTC antes de que se ejecute cada prueba en SomeTest
y restaurará la zona horaria predeterminada después de cada prueba.
Si desea verificar varias zonas horarias, use una regla como esta:
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 );
}
}
Coloque todas las pruebas afectadas en una clase base abstracta AbstractTZTest
y extiéndalo:
public class UTCTest extends AbstractTZTest {
@Rule public TZRule tzRule = new TZRule( DateTimeZone.UTC );
}
Eso ejecutará todas las pruebas en AbstractTZTest
con UTC. Para cada zona horaria que desee probar, necesitará otra clase:
public class UTCTest extends AbstractTZTest {
@Rule public TZRule tzRule = new TZRule( DateTimeZone.forID( "..." );
}
Como los casos de prueba se heredan, eso es todo, solo necesita definir la regla.
De manera similar, puede cambiar el reloj del sistema. Use una regla que llame a DateTimeUtils.setCurrentMillisProvider(...)
para simular que la prueba se ejecuta en un momento determinado y DateTimeUtils.setCurrentMillisSystem()
para restaurar los valores predeterminados.
Nota: su proveedor necesitará una forma de marcar el reloj o todas las nuevas instancias de DateTime
tendrán el mismo valor. A menudo adelanto el valor un milisegundo cada vez que se llama a getMillis()
.
Nota 2: Eso solo funciona con joda-time. No afecta el new java.util.Date()
.
Nota 3: Ya no puede ejecutar estas pruebas en paralelo. Deben ejecutarse en secuencia o uno de ellos probablemente restaure la zona horaria predeterminada mientras se ejecuta otra prueba.
Estoy usando JodaTime 2.1 y estoy buscando un patrón de código de prueba de unidad que realice operaciones de fecha / hora para asegurarme de que se comporte bien para todas las zonas horarias e independiente de DST .
Específicamente:
- ¿Cómo puedo burlarme del reloj del sistema (para no tener que burlarme de todos los lugares donde llamo a
new DateTime()
para obtener la hora actual)? - ¿Cómo puedo hacer lo mismo para la zona horaria predeterminada?
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
}
}
Cambio para una sola prueba
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()
{
//...
}