Prekonanie systémového času na testovanie v Jave

1. Prehľad

V tomto rýchlom návode sa zameriame na rôznymi spôsobmi prepísať systémový čas na testovanie.

Niekedy je v našom kóde logika okolo aktuálneho dátumu. Možno niektoré volania funkcií ako napr nový dátum () alebo Calendar.getInstance (), ktoré sa nakoniec chystajú dovolať System.CurrentTimeMillis.

Pre úvod do používania Hodiny Java, pozrite si prosím tento článok tu. Alebo na použitie AspectJ tu.

2. Používanie aplikácie Hodiny v java.time

The java.time zabaliť v Java 8 obsahuje abstraktnú triedu java.time.Clock s cieľom umožniť zapojenie alternatívnych hodín podľa potreby. Vďaka tomu môžeme pripojiť našu vlastnú implementáciu alebo nájsť tú, ktorá je už vyrobená na uspokojenie našich potrieb.

Aby sme dosiahli naše ciele, vyššie uvedená knižnica obsahuje statické metódy na získanie špeciálnych implementácií. Použijeme dve z nich, ktoré vrátia nemennú implementáciu bezpečnú pre vlákna a serializovateľnú.

Prvý z nich je opravený. Od toho, môžeme získať a Hodiny že sa vráti vždy to isté Okamžité, zabezpečiť, aby testy nezáviseli od aktuálnych hodín.

Na jeho použitie potrebujeme Okamžité a a ZoneOffset:

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

Druhá statická metóda je vyrovnať. V tomto prípade hodiny obklopujú ďalšie hodiny, vďaka ktorým je vrátený objekt schopný získať okamihy, ktoré sú neskôr alebo skôr o zadané trvanie.

Inými slovami, je možné simulovať beh v budúcnosti, v minulosti alebo v ľubovoľnom časovom okamihu:

Clock constantClock = Clock.fixed (ofEpochMilli (0), ZoneId.systemDefault ()); // prechod do budúcnosti: Clock clock = Clock.offset (constantClock, Duration.ofSeconds (10)); // pretočiť späť so zápornou hodnotou: clock = Clock.offset (constantClock, Duration.ofSeconds (-5)); // doba 0 sa vráti na rovnaké hodiny: clock = Clock.offset (constClock, Duration.ZERO);

Vďaka Trvanie triedy, je možné manipulovať od nanosekúnd po dni. Môžeme tiež negovať trvanie, čo znamená získať kópiu tohto trvania s negovanou dĺžkou.

3. Používanie programovania orientovaného na pomer strán

Ďalším spôsobom, ako prepísať systémový čas, je AOP. S týmto prístupom sme schopní utkať Systém triedy, aby vrátila preddefinovanú hodnotu, ktorú môžeme nastaviť v našich testovacích prípadoch.

Je tiež možné prepojiť triedy aplikácií s presmerovaním volania na System.currentTimeMillis () alebo k nový dátum () do inej vlastnej úžitkovej triedy.

Jedným zo spôsobov, ako to implementovať, je použitie AspectJ:

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

Vo vyššie uvedenom príklade chytáme každé volanie System.currentTimeMillis() vo vnútri určeného balíka, čo v tomto prípade je user.code.base.pckg. *, a vrátiť nulu vždy, keď sa stane táto udalosť.

Na tomto mieste môžeme deklarovať vlastnú implementáciu, aby sme získali požadovaný čas v milisekundách.

Jednou z výhod používania AspectJ je, že pracuje priamo na úrovni bytecode, takže na svoju prácu nepotrebuje pôvodný zdrojový kód.

Z tohto dôvodu by sme to nemuseli prekompilovať.

4. Vysmievanie sa Okamžité. Teraz () Metóda

Môžeme použiť Okamžité triedy, ktorá predstavuje okamžitý bod na časovej osi. Normálne ho môžeme použiť na zaznamenanie časových značiek udalostí v našej aplikácii. The teraz () metóda tejto triedy nám umožňuje získať aktuálny okamih zo systémových hodín v časovom pásme UTC.

Pozrime sa na niektoré alternatívy zmeny jeho správania, keď testujeme.

4.1. Preťaženie teraz () S Hodiny

Môžeme preťažiť teraz () metóda s pevnou Hodiny inštancia. Mnohé z tried v java.time balíček majú a teraz () metóda, ktorá vyžaduje a Hodiny parameter, čo z tohto robí náš preferovaný prístup:

@Test public void givenFixedClock_whenNow_thenGetFixedInstant () {String instantExected = "2014-12-22T10: 15: 30Z"; Hodiny hodiny = Clock.fixed (Instant.parse (instantExected), ZoneId.of ("UTC")); Instant instant = Instant.now (hodiny); assertThat (instant.toString ()). isEqualTo (instantExected); }

4.2. Použitím PowerMock

Okrem toho, ak potrebujeme upraviť správanie teraz () metódu bez zasielania parametrov, môžeme použiť PowerMock:

@RunWith (PowerMockRunner.class) @PrepareForTest ({Instant.class}) verejná trieda InstantUnitTest {@Test public void givenInstantMock_whenNow_thenGetFixedInstant () {String instantExposed = "2014-12-22T10: 15: 30Z"; Hodiny hodiny = Clock.fixed (Instant.parse (instantExected), ZoneId.of ("UTC")); Instant instant = Instant.now (hodiny); mockStatic (Okamžitá.trieda); when (Instant.now ()). thenReturn (instant); Okamžité hneď = Instant.now (); assertThat (now.toString ()). isEqualTo (instantExected); }}

4.3. Použitím JMockit

Prípadne môžeme použiť JMockit knižnica.

JMockit nám ponúka dva spôsoby zosmiešňovania statickej metódy. Jeden používa MockUp trieda:

@Test public void givenInstantWithJMock_whenNow_thenGetFixedInstant () {String instantExected = "2014-12-21T10: 15: 30Z"; Hodiny hodiny = Clock.fixed (Instant.parse (instantExected), ZoneId.of ("UTC")); new MockUp () {@Mock public Instant now () {return Instant.now (clock); }}; Okamžité hneď = Instant.now (); assertThat (now.toString ()). isEqualTo (instantExected); }

A ďalší používa Očakávania trieda:

@Test public void givenInstantWithExpectations_whenNow_thenGetFixedInstant () {Clock clock = Clock.fixed (Instant.parse ("2014-12-23T10: 15: 30,00Z"), ZoneId.of ("UTC")); Okamžité instantExected = Instant.now (hodiny); new Expectations (Instant.class) {{Instant.now (); výsledok = instantExčakaný; }}; Okamžité hneď = Instant.now (); assertThat (teraz) .isEqualTo (instantExected); }

5. Vysmievanie sa LocalDateTime.now () Metóda

Ďalšia užitočná trieda v java.time balíček je LocalDateTime trieda. Táto trieda predstavuje v kalendárnom systéme ISO-8601 dátum a čas bez časového pásma. The teraz () metóda tejto triedy nám umožňuje získať aktuálny dátum a čas zo systémových hodín v predvolenom časovom pásme.

Môžeme použiť rovnaké alternatívy na zosmiešnenie, ako sme videli predtým. Napríklad preťaženie teraz () s pevným Hodiny:

@Test public void givenFixedClock_whenNow_thenGetFixedLocalDateTime () {Clock clock = Clock.fixed (Instant.parse ("2014-12-22T10: 15: 30,00Z"), ZoneId.of ("UTC")); Reťazec dateTimeExected = "2014-12-22T10: 15: 30"; LocalDateTime dateTime = LocalDateTime.now (hodiny); assertThat (dateTime) .isEqualTo (dateTimeExected); }

6. Záver

V tomto článku sme sa zaoberali rôznymi spôsobmi, ako prepísať systémový čas na testovanie. Najskôr sme sa pozreli na natívny balíček java.time a jeho Hodiny trieda. Ďalej sme videli, ako použiť aspekt na tkanie Systém trieda. Nakoniec sme videli rôzne alternatívy zosmiešňovania teraz () metóda na Okamžité a LocalDateTime triedy.

Ako vždy, vzorky kódu nájdete na GitHub.

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