Menguji dengan Kebenaran Google

1. Gambaran keseluruhan

Kebenaran adalah kerangka pengujian sumber terbuka yang lancar dan fleksibel yang direka untuk menjadikan penegasan ujian dan mesej kegagalan lebih mudah dibaca.

Dalam artikel ini, kita akan meneroka ciri utama kerangka Kebenaran dan menerapkan contoh untuk menunjukkan kemampuannya.

2. Pergantungan Maven

Pertama, kita perlu menambahkan kebenaran dan kebenaran-pelanjutan java8 ke pom.xml kami :

 com.google.truth truth 0.32   com.google.truth.extensions truth-java8-extension 0.32 test 

Anda boleh mendapatkan versi terkini kebenaran dan kebenaran-java8-sambungan di Maven Central.

3. Pengenalan

Kebenaran membolehkan kita menulis pernyataan yang boleh dibaca dan mesej kegagalan untuk pelbagai kelas:

  • Java Standard - primitif, tatasusunan, rentetan, objek, koleksi, bahan pelempar, kelas, dll.
  • Java 8 - Contoh pilihan dan Strim
  • Jambu biji - Objek pilihan , Multimap , Multiset , dan Jadual
  • Jenis tersuai - dengan memperluas kelas Subjek , seperti yang akan kita lihat kemudian

Melalui kelas Truth dan Truth8 , perpustakaan menyediakan kaedah utiliti untuk menulis penegasan yang sesuai dengan subjek , itulah nilai atau objek yang diuji.

Setelah subjek diketahui, Kebenaran dapat memberi alasan pada waktu menyusun mengenai cadangan apa yang diketahui untuk subjek tersebut . Ini memungkinkan untuk mengembalikan pembungkus di sekitar nilai kita yang menyatakan kaedah proposisi khusus untuk subjek tertentu.

Sebagai contoh, semasa menegaskan pada senarai, Truth mengembalikan kaedah IterableSubject yang menentukan kaedah seperti berisi () dan mengandungAnyOf () , antara lain Semasa menegaskan pada Peta , ia mengembalikan MapSubject yang menyatakan kaedah seperti mengandungEntry () dan mengandungKey () .

4. Bermula

Untuk mula menulis penegasan, mari kita mula-mula mengimport titik masuk Kebenaran :

import static com.google.common.truth.Truth.*; import static com.google.common.truth.Truth8.*;

Sekarang, mari tulis kelas sederhana yang akan kami gunakan dalam beberapa contoh berikut:

public class User { private String name = "John Doe"; private List emails = Arrays.asList("[email protected]", "[email protected]"); public boolean equals(Object obj) { if (obj == null || getClass() != obj.getClass()) { return false; } User other = (User) obj; return Objects.equals(this.name, other.name); } // standard constructors, getters and setters }

Perhatikan kaedah custom equals () , di mana kita menyatakan bahawa dua objek Pengguna sama jika namanya.

5. Penegasan Java Standard

Di bahagian ini, kita akan melihat contoh terperinci bagaimana menulis penegasan ujian untuk jenis Java standard.

5.1. Tegasan Objek

Kebenaran menyediakan pembungkus Subjek untuk melakukan penegasan pada objek. Subjek juga merupakan induk dari semua pembungkus lain di perpustakaan dan menyatakan kaedah untuk menentukan apakah Objek , dalam kes kami Pengguna , sama dengan objek lain:

@Test public void whenComparingUsers_thenEqual() { User aUser = new User("John Doe"); User anotherUser = new User("John Doe"); assertThat(aUser).isEqualTo(anotherUser); }

atau jika sama dengan objek tertentu dalam senarai:

@Test public void whenComparingUser_thenInList() { User aUser = new User(); assertThat(aUser).isIn(Arrays.asList(1, 3, aUser, null)); }

atau jika tidak:

@Test public void whenComparingUser_thenNotInList() { // ... assertThat(aUser).isNotIn(Arrays.asList(1, 3, "Three")); }

sama ada batal atau tidak:

@Test public void whenComparingUser_thenIsNull() { User aUser = null; assertThat(aUser).isNull(); } @Test public void whenComparingUser_thenNotNull() { User aUser = new User(); assertThat(aUser).isNotNull(); }

atau jika itu adalah contoh kelas tertentu:

@Test public void whenComparingUser_thenInstanceOf() { // ... assertThat(aUser).isInstanceOf(User.class); }

Terdapat kaedah penegasan lain di kelas Subjek . Untuk mengetahui semuanya, rujuk dokumentasi Subjek .

Pada bahagian berikut, kami akan memberi tumpuan kepada kaedah yang paling relevan untuk setiap jenis sokongan Truth . Namun, perlu diingat bahawa semua kaedah di kelas Subjek juga dapat diterapkan.

5.2. Integer , Float, dan Double Pernyataan-pernyataan

Contoh Integer , Float, dan Double dapat dibandingkan untuk kesamaan:

@Test public void whenComparingInteger_thenEqual() { int anInt = 10; assertThat(anInt).isEqualTo(10); }

jika lebih besar:

@Test public void whenComparingFloat_thenIsBigger() { float aFloat = 10.0f; assertThat(aFloat).isGreaterThan(1.0f); }

atau lebih kecil:

@Test public void whenComparingDouble_thenIsSmaller() { double aDouble = 10.0f; assertThat(aDouble).isLessThan(20.0); }

Selanjutnya , contoh Float dan Double juga dapat diperiksa untuk melihat apakah keadaan tepat atau tidak:

@Test public void whenComparingDouble_thenWithinPrecision() { double aDouble = 22.18; assertThat(aDouble).isWithin(2).of(23d); } @Test public void whenComparingFloat_thenNotWithinPrecision() { float aFloat = 23.04f; assertThat(aFloat).isNotWithin(1.3f).of(100f); }

5.3. BigDecimal Pernyataan-pernyataan

Selain pernyataan umum, jenis ini dapat dibandingkan dengan mengabaikan skala:

@Test public void whenComparingBigDecimal_thenEqualIgnoringScale() { BigDecimal aBigDecimal = BigDecimal.valueOf(1000, 3); assertThat(aBigDecimal).isEqualToIgnoringScale(new BigDecimal(1.0)); }

5.4. Tegasan Boolean

Hanya dua kaedah yang berkaitan yang disediakan, isTrue () dan isFalse () :

@Test public void whenCheckingBoolean_thenTrue() { boolean aBoolean = true; assertThat(aBoolean).isTrue(); }

5.5. Teguran Rentetan

Kita boleh menguji sama ada String bermula dengan teks tertentu:

@Test public void whenCheckingString_thenStartsWith() { String aString = "This is a string"; assertThat(aString).startsWith("This"); }

Di samping itu, kita dapat memeriksa apakah rentetan itu mengandungi String yang diberikan, apakah itu berakhir dengan nilai yang diharapkan atau apakah itu kosong. Kes ujian untuk ini dan kaedah lain terdapat dalam kod sumber.

5.6. Tegasan Array

We can check Arrays to see if they are equal to other arrays:

@Test public void whenComparingArrays_thenEqual() { String[] firstArrayOfStrings = { "one", "two", "three" }; String[] secondArrayOfStrings = { "one", "two", "three" }; assertThat(firstArrayOfStrings).isEqualTo(secondArrayOfStrings); }

or if they are empty:

@Test public void whenCheckingArray_thenEmpty() { Object[] anArray = {}; assertThat(anArray).isEmpty(); }

5.7. Comparable Assertions

Besides testing whether a Comparable is greater than or less than another instance, we can check to see if they are at least a given value:

@Test public void whenCheckingComparable_thenAtLeast() { Comparable aComparable = 5; assertThat(aComparable).isAtLeast(1); }

Also, we can test whether they are within a particular range:

@Test public void whenCheckingComparable_thenInRange() { // ... assertThat(aComparable).isIn(Range.closed(1, 10)); }

or in a particular list:

@Test public void whenCheckingComparable_thenInList() { // ... assertThat(aComparable).isIn(Arrays.asList(4, 5, 6)); }

We can also test if two Comparable instances are equivalent according to the class's compareTo() method.

First, let's modify our User class to implement the Comparable interface:

public class User implements Comparable { // ... public int compareTo(User o) { return this.getName().compareToIgnoreCase(o.getName()); } }

Now, let's assert that two users with the same name are equivalent:

@Test public void whenComparingUsers_thenEquivalent() { User aUser = new User(); aUser.setName("John Doe"); User anotherUser = new User(); anotherUser.setName("john doe"); assertThat(aUser).isEquivalentAccordingToCompareTo(anotherUser); }

5.8. Iterable Assertions

In addition to asserting the size of an Iterable instance, whether it's empty or has no duplicates, most typical assertions on an Iterable are that it contains some element:

@Test public void whenCheckingIterable_thenContains() { List aList = Arrays.asList(4, 5, 6); assertThat(aList).contains(5); }

that it contains any element of another Iterable:

@Test public void whenCheckingIterable_thenContainsAnyInList() { List aList = Arrays.asList(1, 2, 3); assertThat(aList).containsAnyIn(Arrays.asList(1, 5, 10)); }

and that the subject has the same elements, in the same order, like another:

@Test public void whenCheckingIterable_thenContainsExactElements() { List aList = Arrays.asList("10", "20", "30"); List anotherList = Arrays.asList("10", "20", "30"); assertThat(aList) .containsExactlyElementsIn(anotherList) .inOrder(); }

and if it's ordered using a custom comparator:

@Test public void givenComparator_whenCheckingIterable_thenOrdered() { Comparator aComparator = (a, b) -> new Float(a).compareTo(new Float(b)); List aList = Arrays.asList("1", "012", "0020", "100"); assertThat(aList).isOrdered(aComparator); }

5.9. Map Assertions

In addition to asserting that a Map instance is empty or not, or has a specific size; we can check if it has a specific entry:

@Test public void whenCheckingMap_thenContainsEntry() { Map aMap = new HashMap(); aMap.put("one", 1L); assertThat(aMap).containsEntry("one", 1L); }

if it has a specific key:

@Test public void whenCheckingMap_thenContainsKey() { // ... assertThat(map).containsKey("one"); }

or if it has the same entries as another Map:

@Test public void whenCheckingMap_thenContainsEntries() { Map aMap = new HashMap(); aMap.put("first", 1L); aMap.put("second", 2.0); aMap.put("third", 3f); Map anotherMap = new HashMap(aMap); assertThat(aMap).containsExactlyEntriesIn(anotherMap); }

5.10. Exception Assertions

Only two methods of importance are provided for Exception objects.

We can write assertions addressed to the cause of the exception:

@Test public void whenCheckingException_thenInstanceOf() { Exception anException = new IllegalArgumentException(new NumberFormatException()); assertThat(anException) .hasCauseThat() .isInstanceOf(NumberFormatException.class); }

or to its message:

@Test public void whenCheckingException_thenCauseMessageIsKnown() { Exception anException = new IllegalArgumentException("Bad value"); assertThat(anException) .hasMessageThat() .startsWith("Bad"); }

5.11. Class Assertions

There's only one important method for Class assertions with which we can test whether a class is assignable to another:

@Test public void whenCheckingClass_thenIsAssignable() { Class aClass = Double.class; assertThat(aClass).isAssignableTo(Number.class); }

6. Java 8 Assertions

Optional and Stream are the only two Java 8 types that Truth supports.

6.1. Optional Assertions

There are three important methods to verify an Optional.

We can test whether it has a particular value:

@Test public void whenCheckingJavaOptional_thenHasValue() { Optional anOptional = Optional.of(1); assertThat(anOptional).hasValue(1); }

if the value is present:

@Test public void whenCheckingJavaOptional_thenPresent() { Optional anOptional = Optional.of("Baeldung"); assertThat(anOptional).isPresent(); }

or if the value is not present:

@Test public void whenCheckingJavaOptional_thenEmpty() { Optional anOptional = Optional.empty(); assertThat(anOptional).isEmpty(); }

6.2. Stream Assertions

Assertions for a Stream are very similar to the ones for an Iterable.

For example, we can test if a particular Stream contains all objects of an Iterable in the same order:

@Test public void whenCheckingStream_thenContainsInOrder() { Stream anStream = Stream.of(1, 2, 3); assertThat(anStream) .containsAllOf(1, 2, 3) .inOrder(); }

For more examples, please refer to the Iterable Assertions section.

7. Guava Assertions

In this section, we'll see examples of assertions for the supported Guava types in Truth.

7.1. Optional Assertions

There are also three important assertion methods for a Guava Optional. The hasValue() and isPresent() methods behave exactly as with a Java 8 Optional.

But instead of isEmpty() to assert that an Optional is not present, we use isAbsent():

@Test public void whenCheckingGuavaOptional_thenIsAbsent() { Optional anOptional = Optional.absent(); assertThat(anOptional).isAbsent(); }

7.2. Multimap Assertions

Multimap and standard Map assertions are very similar.

One notable difference is that we can get the multiple values of a key within a Multimap and make assertions on those values.

Here's an example that tests if the values of the “one” key have a size of two:

@Test public void whenCheckingGuavaMultimap_thenExpectedSize() { Multimap aMultimap = ArrayListMultimap.create(); aMultimap.put("one", 1L); aMultimap.put("one", 2.0); assertThat(aMultimap) .valuesForKey("one") .hasSize(2); }

For more examples, please refer to the Map Assertions section.

7.3. Multiset Assertions

Assertions for Multiset objects include the ones for an Iterable and one extra method to verify if a key has a particular number of occurrences:

@Test public void whenCheckingGuavaMultiset_thenExpectedCount() { TreeMultiset aMultiset = TreeMultiset.create(); aMultiset.add("baeldung", 10); assertThat(aMultiset).hasCount("baeldung", 10); }

7.4. Table Assertions

Besides checking its size or where it's empty, we can check a Table to verify if it contains a particular mapping for a given row and column:

@Test public void whenCheckingGuavaTable_thenContains() { Table aTable = TreeBasedTable.create(); aTable.put("firstRow", "firstColumn", "baeldung"); assertThat(aTable).contains("firstRow", "firstColumn"); }

or if it contains a particular cell:

@Test public void whenCheckingGuavaTable_thenContainsCell() { Table aTable = getDummyGuavaTable(); assertThat(aTable).containsCell("firstRow", "firstColumn", "baeldung"); }

Furthermore, we can check if it contains a given row, column, or value. See the source code for the relevant test cases.

8. Custom Failure Messages and Labels

When an assertion fails, Truth displays very readable messages denoting exactly what went wrong. However, sometimes is necessary to add more information to those messages to provide more details about what happened.

Truth allows us to customize those failure messages:

@Test public void whenFailingAssertion_thenCustomMessage() { assertWithMessage("TEST-985: Secret user subject was NOT null!") .that(new User()) .isNull(); }

After running the test, we get the following output:

TEST-985: Secret user subject was NOT null!: Not true that <[email protected]> is null

Also, we can add a custom label that gets displayed before our subject in error messages. This may come in handy when an object does not have a helpful string representation:

@Test public void whenFailingAssertion_thenMessagePrefix() { User aUser = new User(); assertThat(aUser) .named("User [%s]", aUser.getName()) .isNull(); }

If we run the test, we can see the following output:

Not true that User [John Doe] (<[email protected]>) is null

9. Extensions

Extending Truth means we can add support for custom types. To do this, we need to create a class that:

  • extends the Subject class or one of its subclasses
  • defines a constructor that accepts two arguments – a FailureStrategy and an instance of our custom type
  • declares a field of SubjectFactory type, which Truth will use to create instances of our custom subject
  • implements a static assertThat() method that accepts our custom type
  • exposes our test assertion API

Now that we know how to extend Truth, let's create a class that adds support for objects of type User:

public class UserSubject extends ComparableSubject { private UserSubject( FailureStrategy failureStrategy, User target) { super(failureStrategy, target); } private static final SubjectFactory USER_SUBJECT_FACTORY = new SubjectFactory() { public UserSubject getSubject( FailureStrategy failureStrategy, User target) { return new UserSubject(failureStrategy, target); } }; public static 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); } } public IterableSubject emails() { return Truth.assertThat(actual().getEmails()); } }

Now, we can statically import the assertThat() method of our custom subject and write some tests:

@Test public void whenCheckingUser_thenHasName() { User aUser = new User(); assertThat(aUser).hasName("John Doe"); } @Test public void whenCheckingUser_thenHasNameIgnoringCase() { // ... assertThat(aUser).hasNameIgnoringCase("john doe"); } @Test public void givenUser_whenCheckingEmails_thenExpectedSize() { // ... assertThat(aUser) .emails() .hasSize(2); }

10. Conclusion

Dalam tutorial ini, kami meneroka kemungkinan yang diberikan oleh Kebenaran kepada kami untuk menulis lebih banyak ujian dan mesej kegagalan yang dapat dibaca.

Kami mempamerkan kaedah penegasan yang paling popular untuk jenis Java dan Jambu yang disokong, pesanan kegagalan yang disesuaikan, dan Kebenaran yang diperluas dengan subjek tersuai.

Seperti biasa, kod sumber lengkap untuk artikel ini boleh didapati di Github.