Test med Google Truth

1. Oversigt

Sandhed er en flydende og fleksibel open source testramme designet til at gøre testpåstande og fejlmeddelelser mere læsbare.

I denne artikel undersøger vi nøglefunktionerne i Sandhed ramme og implementere eksempler for at fremvise dets evner.

2. Maven-afhængigheder

Først skal vi tilføje sandhed og sandhed-java8-udvidelse til vores pom.xml:

 com.google.truth sandhed 0.32 com.google.truth.extensions sandhed-java8-udvidelse 0.32 test 

Du kan finde de nyeste versioner af sandhed og sandhed-java8-udvidelse på Maven Central.

3. Introduktion

Sandhed giver os mulighed for at skrive læsbare påstande og fejlmeddelelser til en række forskellige klasser:

  • Standard Java - primitiver, arrays, strenge, objekter, samlinger, kastekasser, klasser osv.
  • Java 8Valgfri og Strøm tilfælde
  • GuavaValgfri, Multimap, Multisætog Bord genstande
  • Brugerdefinerede typer - ved at udvide Emne klasse, som vi vil se senere

Gennem Sandhed og Sandhed8 klasser, giver biblioteket hjælpemetoder til at skrive påstande, der fungerer på en emne, det er værdien eller objektet, der testes.

Når emnet er kendt, Sandhed kan redegøre ved kompileringstidspunkt for, hvilke forslag der er kendt for det emne. Dette giver det mulighed for at returnere indpakninger omkring vores værdi, der erklærer forslagsmetoder, der er specifikke for det pågældende emne.

For eksempel når du hævder på en liste, Sandhed returnerer en IterableSubject eksempel definerer metoder som indeholder() og indeholderAnyOf (), blandt andre. Når man hævder en Kort, det returnerer en MapSubject der erklærer metoder som indeholderEntry () og indeholderKey ().

4. Kom godt i gang

Lad os først importere for at begynde at skrive påstande Sandhed'S indgangspunkter:

importer statisk com.google.common.truth.Truth. *; importer statisk com.google.common.truth.Truth8. *;

Lad os nu skrive en simpel klasse, som vi bruger i et par af eksemplerne, der følger:

offentlig klasse bruger {private String name = "John Doe"; private liste-e-mails = Arrays.asList ("[email protected]", "[email protected]"); offentlige boolske er lig med (Objekt obj) {hvis (obj == null || getClass ()! = obj.getClass ()) {return false; } Bruger anden = (Bruger) obj; returnere Objects.equals (dette.navn, andet.navn); } // standardkonstruktører, getters og settere}

Bemærk skikken lige med() metode, hvor vi angiver, at to Bruger objekter er ens, hvis deres navne er.

5. Standard Java-påstande

I dette afsnit vil vi se detaljerede eksempler på, hvordan man skriver testpåstande for standard Java-typer.

5.1. Objekt Påstande

Sandhed giver den Emne indpakning til udførelse af påstande om objekter. Emne er også forælder til alle andre indpakninger i biblioteket og erklærer metoder til at afgøre, om en Objekt, i vores tilfælde a Bruger, er lig med et andet objekt:

@Test offentligt ugyldigt nårComparingUsers_thenEqual () {User aUser = new User ("John Doe"); Bruger anotherUser = ny bruger ("John Doe"); assertThat (aUser) .isEqualTo (anotherUser); }

eller hvis det er lig med et givet objekt på en liste:

@Test offentlig ugyldig nårComparingUser_thenInList () {User aUser = new User (); assertThat (aUser) .isIn (Arrays.asList (1, 3, aUser, null)); }

eller hvis det ikke er:

@Test offentlig ugyldig nårComparingUser_thenNotInList () {// ... assertThat (aUser) .isNotIn (Arrays.asList (1, 3, "Three")); }

hvis det er nul eller ej:

@Test offentligt ugyldigt nårComparingUser_thenIsNull () {User aUser = null; assertThat (aUser) .isNull (); } @Test offentlig ugyldig nårComparingUser_thenNotNull () {User aUser = new User (); assertThat (aUser) .isNotNull (); }

eller hvis det er en forekomst af en bestemt klasse:

@Test offentligt ugyldigt nårComparingUser_thenInstanceOf () {// ... assertThat (aUser) .isInstanceOf (User.class); }

Der er andre påstande metoder i Emne klasse. For at finde dem alle henvises til Emne dokumentation.

I de følgende afsnit, vi vil fokusere på de mest relevante metoder for hver bestemt typeSandhed bakker op. Husk dog, at alle metoder i Emne klasse kan også anvendes.

5.2. Heltal, Flyde, og Dobbelt Påstande

Heltal, Flyde, og Dobbelt tilfælde kan sammenlignes for ligestilling:

@Test offentlig ugyldig nårComparingInteger_thenEqual () {int anInt = 10; hævder, at (anInt) .isEqualTo (10); }

hvis de er større:

@Test offentlig ugyldig nårComparingFloat_thenIsBigger () {float aFloat = 10.0f; hævder, at (aFloat) .isGreaterThan (1.0f); }

eller mindre:

@Test offentlig ugyldig nårComparingDouble_thenIsSmaller () {dobbelt aDouble = 10.0f; hævder, at (aDobbelt) .isLessThan (20.0); }

desuden, Flyde og Dobbelt tilfælde kan også kontrolleres for at se, om de er inden for en forventet præcision eller ej:

@Test offentlig ugyldig nårComparingDouble_thenWithinPrecision () {dobbelt aDouble = 22.18; hævder, at (aDobbelt) .is inden for (2) .af (23d); } @Test offentlig ugyldig nårComparingFloat_thenNotWithinPrecision () {float aFloat = 23.04f; hævder, at (aFloat) .isNotWithin (1.3f) .of (100f); }

5.3. BigDecimal Påstande

Udover de almindelige påstande kan denne type sammenlignes med ignorering af dens skala:

@Test offentlig ugyldig nårComparingBigDecimal_thenEqualIgnoringScale () {BigDecimal aBigDecimal = BigDecimal.valueOf (1000, 3); assertThat (aBigDecimal) .isEqualToIgnoringScale (ny BigDecimal (1.0)); }

5.4. Boolsk Påstande

Der gives kun to relevante metoder, er sandt() og isFalse ():

@Test offentlig ugyldig nårCheckingBoolean_thenTrue () {boolean aBoolean = true; hævder, at (aBoolean) .isTrue (); }

5.5. Snor Påstande

Vi kan teste, om en Snor starter med en bestemt tekst:

@Test offentlig ugyldig nårCheckingString_thenStartsWith () {String aString = "Dette er en streng"; assertThat (aString) .startsWith ("This"); }

Derudover kan vi kontrollere, om strengen indeholder en given streng, om den ender med en forventet værdi, eller om den er tom. Testcases for disse og andre metoder er tilgængelige i kildekoden.

5.6. Array påstande

Vi kan tjekke Arrays for at se, om de er lig med andre arrays:

@Test offentlig ugyldig nårComparingArrays_thenEqual () {String [] firstArrayOfStrings = {"one", "two", "three"}; String [] secondArrayOfStrings = {"one", "two", "three"}; assertThat (firstArrayOfStrings) .isEqualTo (secondArrayOfStrings); }

eller hvis de er tomme:

@Test offentligt ugyldigt nårCheckingArray_thenEmpty () {Object [] anArray = {}; hævder, at (anArray). er tom (); }

5.7. Sammenlignelig Påstande

Udover at teste, om en Sammenlignelig er større end eller mindre end en anden forekomst, kan vi kontrollere, om de mindst har en given værdi:

@Test offentlig ugyldig nårCheckingComparable_thenAtLeast () {Comparable aComparable = 5; hævder, at (aComparable) .isAtLeast (1); }

Vi kan også teste, om de er inden for et bestemt interval:

@Test offentlig ugyldig nårCheckingComparable_thenInRange () {// ... assertThat (aComparable) .isIn (Range.closed (1, 10)); }

eller på en bestemt liste:

@Test offentlig ugyldigt nårCheckingComparable_thenInList () {// ... assertThat (aComparable) .isIn (Arrays.asList (4, 5, 6)); }

Vi kan også teste, om to Sammenlignelig tilfælde er ækvivalente i henhold til klassens sammenligne med() metode.

Lad os først ændre vores Bruger klasse til at gennemføre Sammenlignelig grænseflade:

offentlig klasse Brugerimplementer Sammenlignelig {// ... public int CompareTo (User o) {return this.getName (). CompareToIgnoreCase (o.getName ()); }}

Lad os nu hævde, at to brugere med samme navn er ækvivalente:

@Test offentlig ugyldig nårComparingUsers_thenEquivalent () {User aUser = new User (); aUser.setName ("John Doe"); Bruger anotherUser = ny bruger (); anotherUser.setName ("john doe"); assertThat (aUser) .isEquivalentAccordingToCompareTo (anotherUser); }

5.8. Iterabel Påstande

Ud over at hævde størrelsen på en Iterabel for eksempel, om det er tomt eller ikke har dubletter, mest typiske påstande om en Iterabel er, at den indeholder et eller andet element:

@Test offentlig ugyldig nårCheckingIterable_thenContains () {List aList = Arrays.asList (4, 5, 6); assertThat (aList). indeholder (5); }

at det indeholder ethvert element i et andet Iterabel:

@Test offentlig ugyldig nårCheckingIterable_thenContainsAnyInList () {List aList = Arrays.asList (1, 2, 3); assertThat (aList) .containsAnyIn (Arrays.asList (1, 5, 10)); }

og at motivet har de samme elementer i samme rækkefølge som et andet:

@Test offentlig ugyldig nårCheckingIterable_thenContainsExactElements () {List aList = Arrays.asList ("10", "20", "30"); Vis en anden liste = Arrays.asList ("10", "20", "30"); assertThat (aList) .containsExactlyElementsIn (anotherList) .inOrder (); }

og hvis det bestilles ved hjælp af en brugerdefineret komparator:

@Test offentlig ugyldighed givetComparator_whenCheckingIterable_thenOrdered () {Comparator aComparator = (a, b) -> new Float (a) .compareTo (new Float (b)); Liste aList = Arrays.asList ("1", "012", "0020", "100"); assertThat (aList) .isOrdered (aComparator); }

5.9. Kort Påstande

Ud over at hævde, at en Kort forekomst er tom eller ej, eller har en bestemt størrelse; vi kan kontrollere, om den har en bestemt post:

@Test offentlig ugyldig nårCheckingMap_thenContainsEntry () {Map aMap = new HashMap (); aMap.put ("en", 1L); assertThat (aMap) .containsEntry ("one", 1L); }

hvis den har en bestemt nøgle:

@Test offentligt ugyldigt nårCheckingMap_thenContainsKey () {// ... assertThat (map) .containsKey ("one"); }

eller hvis den har de samme poster som en anden Kort:

@Test offentlig ugyldig nårCheckingMap_thenContainsEntries () {Map aMap = new HashMap (); aMap.put ("første", 1L); aMap.put ("anden", 2.0); aMap.put ("tredje", 3f); Kortlæg anotherMap = nyt HashMap (aMap); assertThat (aMap) .containsExactlyEntriesIn (anotherMap); }

5.10. Undtagelse Påstande

Der er kun fastsat to vigtige metoder Undtagelse genstande.

Vi kan skrive påstande rettet mod årsagen til undtagelsen:

@Test offentlig ugyldig nårCheckingException_thenInstanceOf () {Undtagelse anException = ny IllegalArgumentException (nyt NumberFormatException ()); assertThat (anException) .hasCauseThat () .isInstanceOf (NumberFormatException.class); }

eller til dens meddelelse:

@Test offentlig ugyldig nårCheckingException_thenCauseMessageIsKnown () {Undtagelse anException = ny IllegalArgumentException ("Dårlig værdi"); assertThat (anException) .hasMessageThat () .startsWith ("Bad"); }

5.11. Klasse Påstande

Der er kun en vigtig metode til Klasse påstande, hvormed vi kan teste, om en klasse kan tildeles en anden:

@Test offentlig ugyldig nårCheckingClass_thenIsAssignable () {Class aClass = Double.class; assertThat (aClass) .isAssignableTo (Number.class); }

6. Java 8 påstande

Valgfri og Strøm er de eneste to Java 8 typer, der Sandhed bakker op.

6.1. Valgfri Påstande

Der er tre vigtige metoder til at verificere en Valgfri.

Vi kan teste, om det har en bestemt værdi:

@Test offentlig ugyldig nårCheckingJavaOptional_thenHasValue () {Valgfri anOptional = Optional.of (1); hævder, at (en valgfri) .har værdi (1); }

hvis værdien er til stede:

@Test offentligt ugyldigt nårCheckingJavaOptional_thenPresent () {Optional anOptional = Optional.of ("Baeldung"); assertThat (anOptional) .isPresent (); }

eller hvis værdien ikke er til stede:

@Test offentlig ugyldig nårCheckingJavaOptional_thenEmpty () {Valgfri anOptional = Optional.empty (); hævder, at (en valgfri) .is tom (); }

6.2. Strøm Påstande

Påstande om en Strøm er meget lig dem til en Iterabel.

For eksempel kan vi teste, om en bestemt Strøm indeholder alle objekter af en Iterabel i samme rækkefølge:

@Test offentlig ugyldig nårCheckingStream_thenContainsInOrder () {Stream anStream = Stream.of (1, 2, 3); assertThat (anStream) .containsAllOf (1, 2, 3) .inOrder (); }

For flere eksempler henvises til Iterabel Påstande sektion.

7. Guava-påstande

I dette afsnit ser vi eksempler på påstande om de understøttede Guava-typer i Sandhed.

7.1. Valgfri Påstande

Der er også tre vigtige påstandsmetoder for en Guava Valgfri. Det hasValue () og er til stede() metoder opfører sig nøjagtigt som med en Java 8 Valgfri.

Men i stedet for er tom() at hævde, at en Valgfri ikke er til stede, bruger vi isAbsent ():

@Test offentligt ugyldigt nårCheckingGuavaOptional_thenIsAbsent () {Valgfri anOptional = Optional.absent (); hævder, at (en valgfri) .isAbsent (); }

7.2. Multimap Påstande

Multimap og standard Kort påstande er meget ens.

En bemærkelsesværdig forskel er, at vi kan få flere værdier for en nøgle inden for a Multimap og fremsætte påstande om disse værdier.

Her er et eksempel, der tester, om værdierne for "en" -tasten har en størrelse på to:

@Test offentlig ugyldig nårCheckingGuavaMultimap_thenExpectedSize () {Multimap aMultimap = ArrayListMultimap.create (); aMultimap.put ("en", 1L); aMultimap.put ("en", 2.0); assertThat (aMultimap) .valuesForKey ("one") .hasSize (2); }

For flere eksempler henvises til Kort Påstande sektion.

7.3. Multisæt Påstande

Påstande for Multisæt genstande inkluderer dem til en Iterabel og en ekstra metode til at kontrollere, om en nøgle har et bestemt antal forekomster:

@Test offentlig ugyldig nårCheckingGuavaMultiset_thenExpectedCount () {TreeMultiset aMultiset = TreeMultiset.create (); aMultiset.add ("baeldung", 10); assertThat (aMultiset) .hasCount ("baeldung", 10); }

7.4. Bord Påstande

Udover at kontrollere dens størrelse, eller hvor den er tom, kan vi kontrollere en Bord for at kontrollere, om den indeholder en bestemt kortlægning for en given række og kolonne:

@Test offentlig ugyldig nårCheckingGuavaTable_thenContains () {Table aTable = TreeBasedTable.create (); aTable.put ("firstRow", "firstColumn", "baeldung"); assertThat (aTable) .contains ("firstRow", "firstColumn"); }

eller hvis den indeholder en bestemt celle:

@Test offentlig ugyldig nårCheckingGuavaTable_thenContainsCell () {Tabel aTable = getDummyGuavaTable (); assertThat (aTable) .containsCell ("firstRow", "firstColumn", "baeldung"); }

Desuden kan vi kontrollere, om den indeholder en given række, kolonne eller værdi. Se kildekoden for de relevante testsager.

8. Beskeder og etiketter på brugerdefinerede fejl

Når en påstand mislykkes, Sandhed viser meget læsbare meddelelser, der angiver nøjagtigt, hvad der gik galt. Imidlertid er det undertiden nødvendigt at tilføje flere oplysninger til disse beskeder for at give flere detaljer om, hvad der skete.

Sandhed giver os mulighed for at tilpasse disse fejlmeddelelser:

@Test offentlig ugyldig nårFailingAssertion_thenCustomMessage () {assertWithMessage ("TEST-985: Hemmeligt brugeremne var IKKE nul!") .That (ny bruger ()) .isNull (); }

Efter at have kørt testen får vi følgende output:

TEST-985: Hemmeligt brugeremne var IKKE null !: Ikke sandt, at <[email protected]> er null

Vi kan også tilføje en brugerdefineret etiket, der vises før vores emne i fejlmeddelelser. Dette kan være nyttigt, når et objekt ikke har en nyttig strengrepræsentation:

@Test offentlig ugyldig nårFailingAssertion_thenMessagePrefix () {User aUser = new User (); assertThat (aUser) .navngivet ("Bruger [% s]", aUser.getName ()) .isNull (); }

Hvis vi kører testen, kan vi se følgende output:

Ikke sandt, at bruger [John Doe] (<[email protected]>) er nul

9. Udvidelser

Forlænger Sandhed betyder, at vi kan tilføje support til brugerdefinerede typer. For at gøre dette skal vi oprette en klasse, der:

  • udvider Emne klasse eller en af ​​dens underklasser
  • definerer en konstruktør, der accepterer to argumenter - a Fejlstrategi og en forekomst af vores brugerdefinerede type
  • erklærer et felt af SubjectFactory type, hvilken Sandhed vil bruge til at oprette forekomster af vores brugerdefinerede emne
  • implementerer en statisk hævder, at () metode, der accepterer vores brugerdefinerede type
  • afslører vores test påstand API

Nu hvor vi ved, hvordan vi skal udvide Sandhed, lad os oprette en klasse, der tilføjer support til objekter af typen Bruger:

offentlig klasse UserSubject udvider ComparableSubject {private UserSubject (FailureStrategy failureStrategy, User target) {super (failureStrategy, target); } privat statisk endelig SubjectFactory USER_SUBJECT_FACTORY = ny SubjectFactory () {public UserSubject getSubject (FailureStrategy failureStrategy, User target) {return new UserSubject (failureStrategy, target); }}; offentlig statisk UserSubject assertThat (User user) {return Truth.assertAbout (USER_SUBJECT_FACTORY) .that (user); } public void hasName (String name) {if (! actual (). getName (). equals (name)) {fail ("has name", name); }} public void hasNameIgnoringCase (String name) {if (! actual (). getName (). equalsIgnoreCase (name)) {fail ("has name ignoring case", name); }} offentlige IterableSubject-e-mails () {returner Truth.assertThat (faktisk (). getEmails ()); }}

Nu kan vi importere statisk hævder, at () metode til vores brugerdefinerede emne og skriv nogle tests:

@Test offentlig ugyldig nårCheckingUser_thenHasName () {User aUser = new User (); assertThat (aUser) .hasName ("John Doe"); } @Test offentlig ugyldig nårCheckingUser_thenHasNameIgnoringCase () {// ... assertThat (aUser) .hasNameIgnoringCase ("john doe"); } @Test offentlig ugyldighed givenUser_whenCheckingEmails_thenExpectedSize () {// ... assertThat (aUser) .emails () .hasSize (2); }

10. Konklusion

I denne vejledning undersøgte vi mulighederne Sandhed giver os til at skrive mere læsbare tests og fejlmeddelelser.

Vi viste de mest populære påstandsmetoder for understøttede Java- og Guava-typer, tilpassede fejlmeddelelser og udvidet Sandhed med brugerdefinerede emner.

Som altid kan komplet kildekode til denne artikel findes på Github.