Tilsidesættelse af systemtid til test i Java

1. Oversigt

I denne hurtige vejledning fokuserer vi på forskellige måder at tilsidesætte systemets tid til testning på.

Nogle gange er der en logik omkring den aktuelle dato i vores kode. Måske nogle funktionsopkald som f.eks ny dato () eller Calendar.getInstance (), som til sidst vil ringe System.CurrentTimeMillis.

For en introduktion til brugen af Java-urhenvises til denne artikel her. Eller til brug af AspectJ her.

2. Brug af Clock in java.tid

Det java.tid pakke ind Java 8 inkluderer en abstrakt klasse java.tid. ur med det formål at tillade, at alternative ure tilsluttes efter behov. Med det kan vi tilslutte vores egen implementering eller finde en, der allerede er lavet til at tilfredsstille vores behov.

For at nå vores mål ovenstående bibliotek inkluderer statiske metoder til at give specielle implementeringer. Vi skal bruge to af dem, som returnerer en uforanderlig, trådsikker og serialiserbar implementering.

Den første er fast. Fra det, vi kan få en Ur der altid returnerer det samme Øjeblikkelig, sikre, at testene ikke er afhængige af det aktuelle ur.

For at bruge det har vi brug for en Øjeblikkelig og en ZoneOffset:

Instant.now (Clock.fixed (Instant.parse ("2018-08-22T10: 00: 00Z"), ZoneOffset.UTC))

Den anden statiske metode er forskudt. I dette indpakker et ur et andet ur, der gør det til det returnerede objekt, der er i stand til at få øjeblikke, der er senere eller tidligere med den angivne varighed.

Med andre ord, det er muligt at simulere løb i fremtiden, i fortiden eller på ethvert vilkårligt tidspunkt:

Clock constantClock = Clock.fixed (ofEpochMilli (0), ZoneId.systemDefault ()); // gå til fremtiden: Clock clock = Clock.offset (constantClock, Duration.ofSeconds (10)); // spol tilbage med en negativ værdi: clock = Clock.offset (constantClock, Duration.ofSeconds (-5)); // varigheden 0 vender tilbage til det samme ur: ur = Clock.offset (constClock, Duration.ZERO);

Med Varighed klasse, er det muligt at manipulere fra nanosekunder til dage. Vi kan også negere en varighed, hvilket betyder at få en kopi af denne varighed med længden negeret.

3. Brug af aspektorienteret programmering

En anden måde at tilsidesætte systemtiden på er AOP. Med denne tilgang vi er i stand til at væve System klasse for at returnere en foruddefineret værdi, som vi kan indstille i vores testsager.

Det er også muligt at væve applikationsklasser for at omdirigere opkaldet til System.currentTimeMillis () eller til ny dato () til en anden egen brugsklasse.

En måde at implementere dette på er ved brug af AspectJ:

offentligt aspekt ChangeCallsToCurrentTimeInMillisMethod {long around (): call (public static native long java.lang.System.currentTimeMillis ()) && within (user.code.base.pckg. *) {return 0; }} 

I ovenstående eksempel vi fanger hvert opkald til System.currentTimeMillis() inde i en specificeret pakke, hvilket i dette tilfælde er bruger.kode.base.pckg. *, og returnerer nul hver gang denne begivenhed sker.

Det er på dette sted, hvor vi kan erklære vores egen implementering for at opnå den ønskede tid i millisekunder.

En fordel ved at bruge AspectJ er, at det fungerer direkte på bytecode-niveau, så det ikke har brug for den originale kildekode for at fungere.

Af den grund behøver vi ikke at kompilere det igen.

4. Hånende Øjeblikkelig. Nu () Metode

Vi kan bruge Øjeblikkelig klasse til at repræsentere et øjeblikkeligt punkt på tidslinjen. Normalt kan vi bruge det til at registrere tidsstempler for begivenheder i vores ansøgning. Det nu() metode i denne klasse giver os mulighed for at hente det aktuelle øjeblik fra systemuret i UTC-tidszonen.

Lad os se nogle alternativer til at ændre dens adfærd, når vi tester.

4.1. Overbelastning nu() Med en Ur

Vi kan overbelaste nu() metode med en fast Ur eksempel. Mange af klasser i java.tid pakke har en nu() metode, der tager en Ur parameter, hvilket gør dette til vores foretrukne tilgang:

@Test offentlig ugyldighed givenFixedClock_whenNow_thenGetFixedInstant () {String instantExpected = "2014-12-22T10: 15: 30Z"; Urur = Clock.fixed (Instant.parse (instantExpected), ZoneId.of ("UTC")); Øjeblikkelig øjeblikkelig = Øjeblikkelig. Nu (ur); assertThat (instant.toString ()). er EqualTo (instantExpected); }

4.2. Ved brug af PowerMock

Derudover, hvis vi har brug for at ændre adfærd for nu() metode uden at sende parametre, kan vi bruge PowerMock:

@RunWith (PowerMockRunner.class) @PrepareForTest ({Instant.class}) offentlig klasse InstantUnitTest {@Test offentlig ugyldighed givenInstantMock_whenNow_thenGetFixedInstant () {String instantExpected = "2014-12-22T10: 15: 30Z"; Urur = Clock.fixed (Instant.parse (instantExpected), ZoneId.of ("UTC")); Øjeblikkelig øjeblikkelig = Øjeblikkelig. Nu (ur); mockStatic (Instant.class); når (Instant.now ()). derefterReturn (instant); Øjeblikkelig nu = Øjeblikkelig. Nu (); assertThat (now.toString ()). er EqualTo (instantExpected); }}

4.3. Ved brug af JMockit

Alternativt kan vi bruge JMockit bibliotek.

JMockit tilbyder os to måder at spotte en statisk metode på. Den ene bruger MockUp klasse:

@Test offentlig ugyldighed givenInstantWithJMock_whenNow_thenGetFixedInstant () {String instantExpected = "2014-12-21T10: 15: 30Z"; Urur = Clock.fixed (Instant.parse (instantExpected), ZoneId.of ("UTC")); ny MockUp () {@Mock offentlig Øjeblikkelig nu () {returner Instant.now (ur); }}; Øjeblikkelig nu = Øjeblikkelig. Nu (); assertThat (now.toString ()). er EqualTo (instantExpected); }

Og den anden bruger Forventninger klasse:

@Test offentlig ugyldighed givenInstantWithExpectations_whenNow_thenGetFixedInstant () {Clock clock = Clock.fixed (Instant.parse ("2014-12-23T10: 15: 30.00Z"), ZoneId.of ("UTC")); Øjeblikkelig instantExpected = Instant.now (ur); nye forventninger (Instant.class) {{Instant.now (); resultat = instantExpected; }}; Øjeblikkelig nu = Øjeblikkelig. Nu (); assertThat (nu) .isEqualTo (instantExpected); }

5. Hånende LocalDateTime.now () Metode

En anden nyttig klasse i java.tid pakken er LocalDateTime klasse. Denne klasse repræsenterer en dato-tid uden en tidszone i ISO-8601 kalendersystemet. Det nu() metode i denne klasse giver os mulighed for at hente den aktuelle dato-tid fra systemuret i standard tidszone.

Vi kan bruge de samme alternativer til at spotte det, som vi så før. For eksempel overbelastning nu() med en fast Ur:

@Test offentlig ugyldighed givenFixedClock_whenNow_thenGetFixedLocalDateTime () {Clock clock = Clock.fixed (Instant.parse ("2014-12-22T10: 15: 30.00Z"), ZoneId.of ("UTC")); String dateTimeExpected = "2014-12-22T10: 15: 30"; LocalDateTime dateTime = LocalDateTime.now (ur); assertThat (dateTime) .isEqualTo (dateTimeExpected); }

6. Konklusion

I denne artikel har vi undersøgt forskellige måder at tilsidesætte systemets tid til testning. Først så vi på den oprindelige pakke java.tid ogdet er Ur klasse. Derefter så vi, hvordan man anvender et aspekt til at væve System klasse. Endelig så vi forskellige alternativer til at spotte nu() metode til Øjeblikkelig og LocalDateTime klasser.

Som altid kan kodeeksempler findes på GitHub.

$config[zx-auto] not found$config[zx-overlay] not found