8 Replies
  1. 64

    Het dichtst wat is de Clock object. U kunt een Klok-object gebruiken wanneer u maar wilt (of uit het Systeem van de huidige tijd). Alle date.tijd objecten overbelast now methodes die een klok object in de plaats voor de huidige tijd. Zo kunt u gebruik maken van dependency injection te injecteren een Klok met een specifieke tijd:

    public class MyBean {
        private Clock clock;  //dependency inject
        ...
        public void process(LocalDate eventDate) {
          if (eventDate.isBefore(LocalDate.now(clock)) {
            ...
          }
        }
      }

    Zie Klok JavaDoc voor meer details

    • Ja. In het bijzonder, Clock.fixed is handig bij het testen, terwijl Clock.system of Clock.systemUTC gebruikt kunnen worden in de toepassing.
    • Jammer dat er niet een veranderlijk klok die me in staat stelt om het op een niet-tikkende tijd, maar passen die tijd later (u kunt dit doen met joda). Dit zou handig zijn voor het testen van de tijd-gevoelige code, bijvoorbeeld een cache met op tijd gebaseerde processen of van een klasse die events in de toekomst.
    • De klok is een abstracte klasse, kan u uw eigen test Klok uitvoering
    • Ik geloof dat dat is wat we uiteindelijk doen.
  2. 20

    Ik gebruikte een nieuwe klasse te verbergen Clock.fixed creatie en het vereenvoudigen van de tests:

    public class TimeMachine {
    
        private static Clock clock = Clock.systemDefaultZone();
        private static ZoneId zoneId = ZoneId.systemDefault();
    
        public static LocalDateTime now() {
            return LocalDateTime.now(getClock());
        }
    
        public static void useFixedClockAt(LocalDateTime date){
            clock = Clock.fixed(date.atZone(zoneId).toInstant(), zoneId);
        }
    
        public static void useSystemDefaultZoneClock(){
            clock = Clock.systemDefaultZone();
        }
    
        private static Clock getClock() {
            return clock ;
        }
    }
    public class MyClass {
    
        public void doSomethingWithTime() {
            LocalDateTime now = TimeMachine.now();
            ...
        }
    }
    @Test
    public void test() {
        LocalDateTime twoWeeksAgo = LocalDateTime.now().minusWeeks(2);
    
        MyClass myClass = new MyClass();
    
        TimeMachine.useFixedClockAt(twoWeeksAgo);
        myClass.doSomethingWithTime();
    
        TimeMachine.useSystemDefaultZoneClock();
        myClass.doSomethingWithTime();
    
        ...
    }
    • Wat over draad-veiligheid als er meerdere tests worden uitgevoerd in parallel en wijzig de TimeMachine klok?
    • Vervolgens moet u de klok van het geteste object en gebruik deze bij het aanroepen van tijd verwante methoden. En je kon verwijder de getClock() methode en het gebruik van het veld. Deze methode niets toevoegen maar een paar regels code.
    • Banktime of TimeMachine?
  3. 8

    Ik gebruikte een veld

    private Clock clock;

    en dan

    LocalDate.now(clock);

    in mijn productie code. Dan heb ik gebruikt Mockito in mijn unit tests te bespotten de Klok met Klok.vaste():

    @Mock
    private Clock clock;
    private Clock fixedClock;

    Spottende:

    fixedClock = Clock.fixed(Instant.now(), ZoneId.systemDefault());
    doReturn(fixedClock.instant()).when(clock).instant();
    doReturn(fixedClock.getZone()).when(clock).getZone();

    Bewering:

    assertThat(expectedLocalDateTime, is(LocalDate.now(fixedClock)));
  4. 6

    ik vind met behulp van Clock rommel van uw productie code.

    Kunt u gebruik maken van JMockit of PowerMock mock-statische methode aanroepen in uw test code.
    Voorbeeld met JMockit:

    @Test
    public void testSth() {
      LocalDate today = LocalDate.of(2000, 6, 1);
    
      new Expectations(LocalDate.class) {{
          LocalDate.now(); result = today;
      }};
    
      Assert.assertEquals(LocalDate.now(), today);
    }

    BEWERKEN: Na het lezen van de reacties op Jon Skeet ‘ s antwoord op een soortgelijke vraag hier DUS ik ben het niet eens met mijn eigen verleden. Meer dan iets anders het argument mij ervan overtuigd dat je niet parallize proeven wanneer u mock statische methoden.

    U kunt/moet nog steeds gebruik maken van statische spottende als je hebt te maken met legacy code, dat wel.

    • +1 voor “het gebruik van statische spottende voor legacy code” reactie. Dus voor de nieuwe code, worden aangemoedigd om te leunen in de Dependency Injection en het injecteren van een Klok (vast uur voor de test, systeem-Klok voor de productie runtime).
  5. 1

    Hier is een werkende manier om te overschrijven huidige tijd op een specifieke datum voor JUnit testen in een Java-8 web applicatie met EasyMock

    Joda Time is zeker leuk (met dank aan Stephen, Brian, je hebt gemaakt van onze wereld een betere plek), maar ik was het niet toegestaan om het te gebruiken.

    Na wat experimenteren heb ik kwam uiteindelijk met een manier om het bespotten van de tijd naar een specifieke datum in Java 8 java.API met EasyMock

    • zonder Joda Time API
    • en zonder PowerMock.

    Hier is wat gedaan moet worden:

    Wat er gedaan moet worden in de geteste klasse

    Stap 1

    Het toevoegen van een nieuwe java.time.Clock kenmerk op de te testen class MyService en zorg ervoor dat het nieuwe kenmerk wordt geïnitialiseerd op de standaard waarden met een instantiatie blok of een constructor:

    import java.time.Clock;
    import java.time.LocalDateTime;
    
    public class MyService {
      //(...)
      private Clock clock;
      public Clock getClock() { return clock; }
      public void setClock(Clock newClock) { clock = newClock; }
    
      public void initDefaultClock() {
        setClock(
          Clock.system(
            Clock.systemDefaultZone().getZone() 
            //You can just as well use
            //java.util.TimeZone.getDefault().toZoneId() instead
          )
        );
      }
      { initDefaultClock(); } //initialisation in an instantiation block, but 
                              //it can be done in a constructor just as well
      //(...)
    }

    Stap 2

    Injecteren van het nieuwe kenmerk clock in de methode die oproepen voor een huidige datum-tijd. Bijvoorbeeld, in mijn geval moest ik een check uitvoeren of een datum die is opgeslagen in dataase gebeurd LocalDateTime.now(), die ik remplaced met LocalDateTime.now(clock), zoals:

    import java.time.Clock;
    import java.time.LocalDateTime;
    
    public class MyService {
      //(...)
      protected void doExecute() {
        LocalDateTime dateToBeCompared = someLogic.whichReturns().aDate().fromDB();
        while (dateToBeCompared.isBefore(LocalDateTime.now(clock))) {
          someOtherLogic();
        }
      }
      //(...) 
    }

    Wat er gedaan moet worden in de test klasse

    Stap 3

    In de test klasse, het maken van een mock klok object en injecteren in de geteste klasse is bijvoorbeeld net voordat je de geteste methode doExecute(), dan reset het terug vlak daarna, zo:

    import java.time.Clock;
    import java.time.LocalDateTime;
    import java.time.OffsetDateTime;
    import org.junit.Test;
    
    public class MyServiceTest {
      //(...)
      private int year = 2017;  //Be this a specific 
      private int month = 2;    //date we need 
      private int day = 3;      //to simulate.
    
      @Test
      public void doExecuteTest() throws Exception {
        //(...) EasyMock stuff like mock(..), expect(..), replay(..) and whatnot
    
        MyService myService = new MyService();
        Clock mockClock =
          Clock.fixed(
            LocalDateTime.of(year, month, day, 0, 0).toInstant(OffsetDateTime.now().getOffset()),
            Clock.systemDefaultZone().getZone() //or java.util.TimeZone.getDefault().toZoneId()
          );
        myService.setClock(mockClock); //set it before calling the tested method
    
        myService.doExecute(); //calling tested method 
    
        myService.initDefaultClock(); //reset the clock to default right afterwards with our own previously created method
    
        //(...) remaining EasyMock stuff: verify(..) and assertEquals(..)
        }
      }

    Check het in debug-modus en ziet u de datum van 2017 Feb 3 correct werd geïnjecteerd in myService aanleg en gebruikt in de vergelijking instructie en correct is teruggezet naar huidige datum met initDefaultClock().

  6. 0

    Dit voorbeeld toont zelfs hoe te combineren en Direct LocalTime (gedetailleerde uitleg van de problemen met de conversie)

    Een klasse onder test

    import java.time.Clock;
    import java.time.LocalTime;
    
    public class TimeMachine {
    
        private LocalTime from = LocalTime.MIDNIGHT;
    
        private LocalTime until = LocalTime.of(6, 0);
    
        private Clock clock = Clock.systemDefaultZone();
    
        public boolean isInInterval() {
    
            LocalTime now = LocalTime.now(clock);
    
            return now.isAfter(from) && now.isBefore(until);
        }
    
    }

    Een Groovy test

    import org.junit.Test
    import org.junit.runner.RunWith
    import org.junit.runners.Parameterized
    
    import java.time.Clock
    import java.time.Instant
    
    import static java.time.ZoneOffset.UTC
    import static org.junit.runners.Parameterized.Parameters
    
    @RunWith(Parameterized)
    class TimeMachineTest {
    
        @Parameters(name = "{0} - {2}")
        static data() {
            [
                ["01:22:00", true,  "in interval"],
                ["23:59:59", false, "before"],
                ["06:01:00", false, "after"],
            ]*.toArray()
        }
    
        String time
        boolean expected
    
        TimeMachineTest(String time, boolean expected, String testName) {
            this.time = time
            this.expected = expected
        }
    
        @Test
        void test() {
            TimeMachine timeMachine = new TimeMachine()
            timeMachine.clock = Clock.fixed(Instant.parse("2010-01-01T${time}Z"), UTC)
            def result = timeMachine.isInInterval()
            assert result == expected
        }
    
    }
  7. 0

    Ik moet LocalDate exemplaar in plaats van LocalDateTime.

    Met deze reden heb ik gemaakt naar aanleiding van utility klasse:

    public final class Clock {
        private static long time;
    
        private Clock() {
        }
    
        public static void setCurrentDate(LocalDate date) {
            Clock.time = date.toEpochDay();
        }
    
        public static LocalDate getCurrentDate() {
            return LocalDate.ofEpochDay(getDateMillis());
        }
    
        public static void resetDate() {
            Clock.time = 0;
        }
    
        private static long getDateMillis() {
            return (time == 0 ? LocalDate.now().toEpochDay() : time);
        }
    }

    En het gebruik van het net:

    class ClockDemo {
        public static void main(String[] args) {
            System.out.println(Clock.getCurrentDate());
    
            Clock.setCurrentDate(LocalDate.of(1998, 12, 12));
            System.out.println(Clock.getCurrentDate());
    
            Clock.resetDate();
            System.out.println(Clock.getCurrentDate());
        }
    }

    Output:

    2019-01-03
    1998-12-12
    2019-01-03

    Vervangen alle schepping LocalDate.now() te Clock.getCurrentDate() in het project.

    Want het is voorjaar boot toepassing. Voordat test profiel uitvoering net een vooraf gedefinieerde datum voor alle tests:

    public class TestProfileConfigurer implements ApplicationListener<ApplicationPreparedEvent> {
        private static final LocalDate TEST_DATE_MOCK = LocalDate.of(...);
    
        @Override
        public void onApplicationEvent(ApplicationPreparedEvent event) {
            ConfigurableEnvironment environment = event.getApplicationContext().getEnvironment();
            if (environment.acceptsProfiles(Profiles.of("test"))) {
                Clock.setCurrentDate(TEST_DATE_MOCK);
            }
        }
    }

    En toe te voegen aan spring.factories:

    org.springframework.de context.ApplicationListener=com.init.TestProfileConfigurer

  8. 0

    Met de hulp van PowerMockito voor een lente-boot-test kunt u bespotten de ZonedDateTime.
    U hebt het volgende nodig.

    Aantekeningen

    Op de test klasse je nodig hebt voor het bereiden van de service die gebruik maakt van de ZonedDateTime.

    @RunWith(PowerMockRunner.class)
    @PowerMockRunnerDelegate(SpringRunner.class)
    @PrepareForTest({EscalationService.class})
    @SpringBootTest
    public class TestEscalationCases {
      @Autowired
      private EscalationService escalationService;
      //...
    }

    Test case

    In de test kunt u de voorbereiding van een gewenste tijd, en krijgt het in de reactie van de aanroep van de methode.

      @Test
      public void escalateOnMondayAt14() throws Exception {
        ZonedDateTime preparedTime = ZonedDateTime.now();
        preparedTime = preparedTime.with(DayOfWeek.MONDAY);
        preparedTime = preparedTime.withHour(14);
        PowerMockito.mockStatic(ZonedDateTime.class);
        PowerMockito.when(ZonedDateTime.now(ArgumentMatchers.any(ZoneId.class))).thenReturn(preparedTime);
        //... Assertions 
    }

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *