Tengo una prueba de JUnit que falla porque los milisegundos son diferentes. En este caso, no me importan los milisegundos. ¿Cómo puedo cambiar la precisión de la aserción para ignorar milisegundos (o cualquier precisión que me gustaría establecer)?
Ejemplo de una afirmación fallida que me gustaría aprobar:
Date dateOne = new Date();
dateOne.setTime(61202516585000L);
Date dateTwo = new Date();
dateTwo.setTime(61202516585123L);
assertEquals(dateOne, dateTwo);
Otra solución más, lo haría así:
assertTrue("Dates aren't close enough to each other!", (date2.getTime() - date1.getTime()) < 1000);
fuente
Hay bibliotecas que ayudan con esto:
Apache commons-lang
Si tiene Apache commons-lang en su classpath, puede usarlo
DateUtils.truncate
para truncar las fechas en algún campo.Hay una abreviatura para esto:
Tenga en cuenta que 12: 00: 00.001 y 11: 59: 00.999 se truncarán a valores diferentes, por lo que esto podría no ser ideal. Para eso, hay ronda:
AssertJ
A partir de la versión 3.7.0, AssertJ agregó
isCloseTo
aserciones, si está utilizando la API de fecha / hora de Java 8.LocalTime _07_10 = LocalTime.of(7, 10); LocalTime _07_42 = LocalTime.of(7, 42); assertThat(_07_10).isCloseTo(_07_42, within(1, ChronoUnit.HOURS)); assertThat(_07_10).isCloseTo(_07_42, within(32, ChronoUnit.MINUTES));
También funciona con fechas de Java heredadas:
Date d1 = new Date(); Date d2 = new Date(); assertThat(d1).isCloseTo(d2, within(100, ChronoUnit.MILLIS).getValue());
fuente
java.sql.Timestamps
yDateUtils.truncate(...)
funcionó para mí en Java 8. Mi caso particular incluía una tecnología de base de datos que no permitía guardar un grano más fino que un segundo, por lo que estaba comparando una marca de tiempo en memoria con una que se había guardado y recuperado de una base de datos. La marca de tiempo en memoria tuvo mayor precisión que la marca de tiempo que se leyó de la base de datos.Podrías hacer algo como esto:
assertTrue((date1.getTime()/1000) == (date2.getTime()/1000));
No se necesitan comparaciones de cadenas.
fuente
En JUnit puedes programar dos métodos de aserción, como este:
public class MyTest { @Test public void test() { ... assertEqualDates(expectedDateObject, resultDate); // somewhat more confortable: assertEqualDates("01/01/2012", anotherResultDate); } private static final String DATE_PATTERN = "dd/MM/yyyy"; private static void assertEqualDates(String expected, Date value) { DateFormat formatter = new SimpleDateFormat(DATE_PATTERN); String strValue = formatter.format(value); assertEquals(expected, strValue); } private static void assertEqualDates(Date expected, Date value) { DateFormat formatter = new SimpleDateFormat(DATE_PATTERN); String strExpected = formatter.format(expected); String strValue = formatter.format(value); assertEquals(strExpected, strValue); } }
fuente
No sé si hay soporte en JUnit, pero una forma de hacerlo:
import java.text.SimpleDateFormat; import java.util.Date; public class Example { private static SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss"); private static boolean assertEqualDates(Date date1, Date date2) { String d1 = formatter.format(date1); String d2 = formatter.format(date2); return d1.equals(d2); } public static void main(String[] args) { Date date1 = new Date(); Date date2 = new Date(); if (assertEqualDates(date1,date2)) { System.out.println("true!"); } } }
fuente
assertEqualDates
, haré su tipo de retornovoid
y haré la última líneaassertEquals(d1, d2)
. De esta forma se comportaría igual que todos losassert*
métodos JUnit .En realidad, este es un problema más difícil de lo que parece debido a los casos límite en los que la varianza que no le importa cruza un umbral para un valor que está verificando. por ejemplo, la diferencia de milisegundos es inferior a un segundo, pero las dos marcas de tiempo cruzan el segundo umbral, el umbral de los minutos o el umbral de la hora. Esto hace que cualquier enfoque de DateFormat sea inherentemente propenso a errores.
En cambio, sugeriría comparar las marcas de tiempo reales en milisegundos y proporcionar un delta de variación que indique lo que considera una diferencia aceptable entre los dos objetos de fecha. A continuación, se muestra un ejemplo demasiado detallado:
public static void assertDateSimilar(Date expected, Date actual, long allowableVariance) { long variance = Math.abs(allowableVariance); long millis = expected.getTime(); long lowerBound = millis - allowableVariance; long upperBound = millis + allowableVariance; DateFormat df = DateFormat.getDateTimeInstance(); boolean within = lowerBound <= actual.getTime() && actual.getTime() <= upperBound; assertTrue(MessageFormat.format("Expected {0} with variance of {1} but received {2}", df.format(expected), allowableVariance, df.format(actual)), within); }
fuente
Con JUnit 4 también puede implementar un comparador para probar fechas de acuerdo con la precisión elegida. En este ejemplo, el comparador toma una expresión de formato de cadena como parámetro. El código no es más corto para este ejemplo. Sin embargo, la clase de emparejamiento puede reutilizarse; y si le da un nombre descriptivo, puede documentar la intención con la prueba de una manera elegante.
import static org.junit.Assert.assertThat; // further imports from org.junit. and org.hamcrest. @Test public void testAddEventsToBaby() { Date referenceDate = new Date(); // Do something.. Date testDate = new Date(); //assertThat(referenceDate, equalTo(testDate)); // Test on equal could fail; it is a race condition assertThat(referenceDate, sameCalendarDay(testDate, "yyyy MM dd")); } public static Matcher<Date> sameCalendarDay(final Object testValue, final String dateFormat){ final SimpleDateFormat formatter = new SimpleDateFormat(dateFormat); return new BaseMatcher<Date>() { protected Object theTestValue = testValue; public boolean matches(Object theExpected) { return formatter.format(theExpected).equals(formatter.format(theTestValue)); } public void describeTo(Description description) { description.appendText(theTestValue.toString()); } }; }
fuente
use aserciones de AssertJ para Joda-Time ( http://joel-costigliola.github.io/assertj/assertj-joda-time.html )
import static org.assertj.jodatime.api.Assertions.assertThat; import org.joda.time.DateTime; assertThat(new DateTime(dateOne.getTime())).isEqualToIgnoringMillis(new DateTime(dateTwo.getTime()));
el mensaje de prueba fallida es más legible
java.lang.AssertionError: Expecting: <2014-07-28T08:00:00.000+08:00> to have same year, month, day, hour, minute and second as: <2014-07-28T08:10:00.000+08:00> but had not.
fuente
assertThat(new Date(2016 - 1900, 0, 1,12,13,14)).isEqualToIgnoringMillis("2016-01-01T12:13:14");
Si estaba usando Joda, podría usar Fest Joda Time .
fuente
Simplemente compare las partes de la fecha que le interesan comparar:
Date dateOne = new Date(); dateOne.setTime(61202516585000L); Date dateTwo = new Date(); dateTwo.setTime(61202516585123L); assertEquals(dateOne.getMonth(), dateTwo.getMonth()); assertEquals(dateOne.getDate(), dateTwo.getDate()); assertEquals(dateOne.getYear(), dateTwo.getYear()); // alternative to testing with deprecated methods in Date class Calendar calOne = Calendar.getInstance(); Calendar calTwo = Calendar.getInstance(); calOne.setTime(dateOne); calTwo.setTime(dateTwo); assertEquals(calOne.get(Calendar.MONTH), calTwo.get(Calendar.MONTH)); assertEquals(calOne.get(Calendar.DATE), calTwo.get(Calendar.DATE)); assertEquals(calOne.get(Calendar.YEAR), calTwo.get(Calendar.YEAR));
fuente
JUnit tiene una aserción incorporada para comparar dobles y especificar qué tan cerca deben estar. En este caso, el delta está dentro de los milisegundos que considera equivalentes a las fechas. Esta solución no tiene condiciones de límite, mide la varianza absoluta, puede especificar fácilmente la precisión y no requiere que se escriban bibliotecas o código adicional.
Date dateOne = new Date(); dateOne.setTime(61202516585000L); Date dateTwo = new Date(); dateTwo.setTime(61202516585123L); // this line passes correctly Assert.assertEquals(dateOne.getTime(), dateTwo.getTime(), 500.0); // this line fails correctly Assert.assertEquals(dateOne.getTime(), dateTwo.getTime(), 100.0);
Nota Debe ser 100.0 en lugar de 100 (o se necesita un lanzamiento para duplicar) para forzarlo a compararlos como dobles.
fuente
Puede elegir qué nivel de precisión desea al comparar fechas, por ejemplo:
LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS); // e.g. in MySQL db "timestamp" is without fractional seconds precision (just up to seconds precision) assertEquals(myTimestamp, now);
fuente
Algo como esto podría funcionar:
assertEquals(new SimpleDateFormat("dd MMM yyyy").format(dateOne), new SimpleDateFormat("dd MMM yyyy").format(dateTwo));
fuente
En lugar de usarlo
new Date
directamente, puede crear un pequeño colaborador, que puede simular en su prueba:public class DateBuilder { public java.util.Date now() { return new java.util.Date(); } }
Cree un miembro de DateBuilder y cambie las llamadas de
new Date
adateBuilder.now()
import java.util.Date; public class Demo { DateBuilder dateBuilder = new DateBuilder(); public void run() throws InterruptedException { Date dateOne = dateBuilder.now(); Thread.sleep(10); Date dateTwo = dateBuilder.now(); System.out.println("Dates are the same: " + dateOne.equals(dateTwo)); } public static void main(String[] args) throws InterruptedException { new Demo().run(); } }
El método principal producirá:
Dates are the same: false
En la prueba, puede inyectar un talón de
DateBuilder
y dejar que devuelva el valor que desee. Por ejemplo, con Mockito o una clase anónima que anulanow()
:public class DemoTest { @org.junit.Test public void testMockito() throws Exception { DateBuilder stub = org.mockito.Mockito.mock(DateBuilder.class); org.mockito.Mockito.when(stub.now()).thenReturn(new java.util.Date(42)); Demo demo = new Demo(); demo.dateBuilder = stub; demo.run(); } @org.junit.Test public void testAnonymousClass() throws Exception { Demo demo = new Demo(); demo.dateBuilder = new DateBuilder() { @Override public Date now() { return new Date(42); } }; demo.run(); } }
fuente
Convierta las fechas en String usando SimpleDateFromat, especifique en el constructor los campos de fecha / hora requeridos y compare los valores de cadena:
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String expectedDate = formatter.format(dateOne)); String dateToTest = formatter.format(dateTwo); assertEquals(expectedDate, dateToTest);
fuente
Hice una pequeña clase que podría ser útil para algunos googlers que terminan aquí: https://stackoverflow.com/a/37168645/5930242
fuente
Aquí hay una función de utilidad que hizo el trabajo por mí.
private boolean isEqual(Date d1, Date d2){ return d1.toLocalDate().equals(d2.toLocalDate()); }
fuente
lanzo los objetos a java.util.Date y comparo
fuente