lineborder - titledborder java




Vergleichen Sie Datumsobjekte mit unterschiedlicher Genauigkeit (12)

Ich habe einen JUnit-Test, der fehlschlägt, weil sich die Millisekunden unterscheiden. In diesem Fall kümmere ich mich nicht um die Millisekunden. Wie kann ich die Genauigkeit des Asserts ändern, um Millisekunden zu ignorieren (oder eine Genauigkeit, die ich möchte)?

Beispiel für eine fehlerhafte Behauptung, die ich weitergeben möchte:

Date dateOne = new Date();
dateOne.setTime(61202516585000L);
Date dateTwo = new Date();
dateTwo.setTime(61202516585123L);
assertEquals(dateOne, dateTwo);

Anstatt das new Date direkt zu verwenden, können Sie einen kleinen Mitarbeiter erstellen, den Sie in Ihrem Test simulieren 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 in dateBuilder.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 wird produzieren:

Dates are the same: false

Im Test können Sie einen Stub von DateBuilder und es einen beliebigen Wert zurückgeben lassen. Zum Beispiel mit Mockito oder einer anonymen Klasse, die now() überschreibt:

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();
    }
}

AssertJ Assertions für Joda-Time verwenden ( 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 Testnachricht kann nicht gelesen werden

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.

Es gibt Bibliotheken, die dabei helfen:

Apache commons-lang

Wenn Sie in Ihrem Klassenpfad Apache commons-lang haben , können Sie DateUtils.truncate um die Datumsangaben auf ein Feld zu DateUtils.truncate .

assertEquals(DateUtils.truncate(date1,Calendar.SECOND),
             DateUtils.truncate(date2,Calendar.SECOND));

Dafür gibt es eine Abkürzung:

assertTrue(DateUtils.truncatedEquals(date1,date2,Calendar.SECOND));

Beachten Sie, dass 12: 00: 00.001 und 11: 59: 00.999 auf andere Werte gekürzt werden, so dass dies möglicherweise nicht ideal ist. Dafür gibt es Runde:

assertEquals(DateUtils.round(date1,Calendar.SECOND),
             DateUtils.round(date2,Calendar.SECOND));

AssertJ

Ab Version 3.7.0 fügte isCloseTo Assertions hinzu, 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 älteren Java-Dates:

Date d1 = new Date();
Date d2 = new Date();
assertThat(d1).isCloseTo(d2, within(100, ChronoUnit.MILLIS).getValue());

Ich habe einen kleinen Kurs gemacht, der für einige Googler nützlich sein könnte, die hier enden: https://.com/a/37168645/5930242


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!"); }
    }
}

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);
  }
}

Konvertieren Sie die Datumsangaben mithilfe von SimpleDateFromat in String, geben Sie im Konstruktor die erforderlichen Datums- / Uhrzeitfelder an und vergleichen Sie die Stringwerte:

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String expectedDate = formatter.format(dateOne));
String dateToTest = formatter.format(dateTwo);
assertEquals(expectedDate, dateToTest);

Mit JUnit 4 können Sie auch einen Matcher implementieren, um Datumsangaben entsprechend der von Ihnen gewählten Genauigkeit zu testen. In diesem Beispiel nimmt der Matcher einen String-Formatausdruck als Parameter an. 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());
        }
    };
}

Sie können wählen, welche Genauigkeitsstufe Sie beim Vergleichen von Datumsangaben wünschen, 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);

Sie könnten so etwas tun:

assertTrue((date1.getTime()/1000) == (date2.getTime()/1000));

Kein Stringvergleich erforderlich.


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));

Verwenden Sie ein DateFormat Objekt mit einem Format, das nur die Teile enthält, die Sie assertEquals() möchten, und führen Sie assertEquals() für die resultierenden Strings aus. Sie können das auch einfach in Ihre eigene assertDatesAlmostEqual() Methode assertDatesAlmostEqual() .





junit