Ich habe einen JUnit-Test, der fehlschlägt, weil die Millisekunden unterschiedlich sind. In diesem Fall interessieren mich die Millisekunden nicht. Wie kann ich die Genauigkeit der Zusicherung ändern, um Millisekunden zu ignorieren (oder eine Genauigkeit, auf die ich sie einstellen möchte)?
Beispiel für eine fehlerhafte Behauptung, die ich bestehen möchte:
Date dateOne = new Date();
dateOne.setTime(61202516585000L);
Date dateTwo = new Date();
dateTwo.setTime(61202516585123L);
assertEquals(dateOne, dateTwo);
Noch eine Problemumgehung, ich würde es so machen:
assertTrue("Dates aren't close enough to each other!", (date2.getTime() - date1.getTime()) < 1000);
quelle
Es gibt Bibliotheken, die dabei helfen:
Apache commons-lang
Wenn Sie Apache commons-lang in Ihrem Klassenpfad haben, können Sie
DateUtils.truncate
die Daten auf ein Feld kürzen.Dafür gibt es eine Abkürzung:
Beachten Sie, dass 12: 00: 00.001 und 11: 59: 00.999 auf unterschiedliche Werte abgeschnitten werden, sodass dies möglicherweise nicht ideal ist. Dafür gibt es rund:
AssertJ
Ab Version 3.7.0 hat AssertJ Assertions hinzugefügt
isCloseTo
, wenn Sie die Java 8 Date / Time API verwenden.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));
Es funktioniert auch mit alten Java-Daten:
Date d1 = new Date(); Date d2 = new Date(); assertThat(d1).isCloseTo(d2, within(100, ChronoUnit.MILLIS).getValue());
quelle
java.sql.Timestamps
undDateUtils.truncate(...)
arbeitete für mich in Java 8. Mein spezieller Fall beinhaltete eine Datenbanktechnologie, die das Speichern von feinerem Korn als einer Sekunde nicht unterstützte, also verglich ich einen speicherinternen Zeitstempel mit einem gespeicherten und aus einer Datenbank abgerufen. Der speicherinterne Zeitstempel hatte eine höhere Genauigkeit als der aus der Datenbank gelesene Zeitstempel.Sie könnten so etwas tun:
assertTrue((date1.getTime()/1000) == (date2.getTime()/1000));
Keine String-Vergleiche erforderlich.
quelle
In JUnit können Sie zwei Assert-Methoden wie folgt programmieren:
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); } }
quelle
Ich weiß nicht, ob es Unterstützung in JUnit gibt, aber eine Möglichkeit, dies zu tun:
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!"); } } }
quelle
assertEqualDates
würde ich ihren Rückgabetypvoid
und die letzte Zeile erstellenassertEquals(d1, d2)
. Auf diese Weise würde es sich wie alle JUnit-assert*
Methoden verhalten .Dies ist tatsächlich ein schwierigeres Problem, als es aufgrund der Grenzfälle erscheint, in denen die Varianz, die Sie nicht interessieren, einen Schwellenwert für einen Wert überschreitet, den Sie überprüfen. Beispielsweise beträgt die Millisekunden-Differenz weniger als eine Sekunde, aber die beiden Zeitstempel überschreiten die zweite Schwelle oder die Minutenschwelle oder die Stundenschwelle. Dies macht jeden DateFormat-Ansatz von Natur aus fehleranfällig.
Stattdessen würde ich vorschlagen, die tatsächlichen Millisekunden-Zeitstempel zu vergleichen und ein Varianzdelta anzugeben, das angibt, was Sie als akzeptablen Unterschied zwischen den beiden Datumsobjekten betrachten. Es folgt ein übermäßig ausführliches Beispiel:
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); }
quelle
Mit JUnit 4 können Sie auch einen Matcher zum Testen von Daten gemäß der von Ihnen gewählten Genauigkeit implementieren . In diesem Beispiel verwendet der Matcher einen Ausdruck im Zeichenfolgenformat als Parameter. Der Code ist für dieses Beispiel nicht kürzer. Die Matcher-Klasse kann jedoch wiederverwendet werden. und wenn Sie ihm einen beschreibenden Namen geben, können Sie die Absicht mit dem Test auf elegante Weise dokumentieren.
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()); } }; }
quelle
Verwenden Sie AssertJ-Zusicherungen für 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()));
Die Meldung "Test fehlgeschlagen" ist besser lesbar
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.
quelle
assertThat(new Date(2016 - 1900, 0, 1,12,13,14)).isEqualToIgnoringMillis("2016-01-01T12:13:14");
Wenn Sie Joda verwenden, können Sie Fest Joda Time verwenden .
quelle
Vergleichen Sie einfach die Datumsteile, die Sie vergleichen möchten:
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));
quelle
JUnit verfügt über eine integrierte Zusicherung zum Vergleichen von Doppelwerten und zum Festlegen, wie nahe diese sein müssen. In diesem Fall liegt das Delta innerhalb der Anzahl der Millisekunden, die Sie als gleichwertig betrachten. Diese Lösung hat keine Randbedingungen, misst die absolute Varianz, kann leicht die Genauigkeit festlegen und erfordert kein Schreiben zusätzlicher Bibliotheken oder Codes.
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);
Hinweis Es muss 100,0 anstelle von 100 sein (oder es ist eine Umwandlung in Doppel erforderlich), um zu erzwingen, dass sie als Doppel verglichen werden.
quelle
Sie können beim Vergleichen von Daten auswählen, welche Genauigkeitsstufe Sie möchten, z.
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);
quelle
So etwas könnte funktionieren:
assertEquals(new SimpleDateFormat("dd MMM yyyy").format(dateOne), new SimpleDateFormat("dd MMM yyyy").format(dateTwo));
quelle
Anstatt
new Date
direkt zu verwenden, können Sie einen kleinen Mitarbeiter erstellen, den Sie in Ihrem Test verspotten können:public class DateBuilder { public java.util.Date now() { return new java.util.Date(); } }
Erstellen Sie ein DateBuilder-Mitglied und ändern Sie die Aufrufe von
new Date
nachdateBuilder.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(); } }
Die Hauptmethode erzeugt:
Dates are the same: false
Im Test können Sie einen Stub von injizieren
DateBuilder
und ihn einen beliebigen Wert zurückgeben lassen. Zum Beispiel mit Mockito oder einer anonymen Klasse, die Folgendes überschreibtnow()
: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(); } }
quelle
Konvertieren Sie die Daten mit SimpleDateFromat in einen String, geben Sie im Konstruktor die erforderlichen Datums- / Zeitfelder an und vergleichen Sie die String-Werte:
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String expectedDate = formatter.format(dateOne)); String dateToTest = formatter.format(dateTwo); assertEquals(expectedDate, dateToTest);
quelle
Ich habe eine kleine Klasse gemacht, die für einige Googler nützlich sein könnte, die hier landen: https://stackoverflow.com/a/37168645/5930242
quelle
Hier ist eine Utility-Funktion, die den Job für mich erledigt hat.
private boolean isEqual(Date d1, Date d2){ return d1.toLocalDate().equals(d2.toLocalDate()); }
quelle
Ich habe die Objekte in java.util.Date umgewandelt und verglichen
quelle