Class Correspondence<A extends @Nullable Object,E extends @Nullable Object>
- java.lang.Object
-
- com.google.common.truth.Correspondence<A,E>
-
public abstract class Correspondence<A extends @Nullable Object,E extends @Nullable Object> extends Object
Determines whether an instance of typeA
corresponds in some way to an instance of typeE
for the purposes of a test assertion. For example, the implementation returned by thetolerance(double)
factory method implements approximate equality between numeric values, with values being said to correspond if the difference between them does not exceed the given fixed tolerance. The instances of typeA
are typically actual values from a collection returned by the code under test; the instances of typeE
are typically expected values with which the actual values are compared by the test.The correspondence is required to be consistent: for any given values
actual
andexpected
, multiple invocations ofcompare(actual, expected)
must consistently returntrue
or consistently returnfalse
(provided that neither value is modified). AlthoughA
andE
will often be the same types, they are not required to be the same, and even if they are it is not required that the correspondence should have any of the other properties of an equivalence relation (reflexivity, symmetry, or transitivity).Optionally, instances of this class can also provide functionality to format the difference between values which do not correspond. This results in failure messages including formatted diffs between expected and actual value, where possible.
The recommended approach for creating an instance of this class is to use one of the static factory methods. The most general of these is
from(com.google.common.truth.Correspondence.BinaryPredicate<A, E>, java.lang.String)
; the other methods are more convenient in specific cases. The optional diff-formatting functionality can be added usingformattingDiffsUsing(com.google.common.truth.Correspondence.DiffFormatter<? super A, ? super E>)
. (Alternatively, you can subclass this class yourself, but that is generally not recommended.)Instances of this are typically used via
IterableSubject.comparingElementsUsing(com.google.common.truth.Correspondence<? super A, ? super E>)
,MapSubject.comparingValuesUsing(com.google.common.truth.Correspondence<? super A, ? super E>)
, orMultimapSubject.comparingValuesUsing(com.google.common.truth.Correspondence<? super A, ? super E>)
.- Author:
- Pete Gillin
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static interface
Correspondence.BinaryPredicate<A extends @Nullable Object,E extends @Nullable Object>
A functional interface for a binary predicate, to be used to test whether a pair of objects of typesA
andE
satisfy some condition.static interface
Correspondence.DiffFormatter<A extends @Nullable Object,E extends @Nullable Object>
A functional interface to be used format the diff between a pair of objects of typesA
andE
.
-
Method Summary
All Methods Static Methods Instance Methods Abstract Methods Concrete Methods Deprecated Methods Modifier and Type Method Description abstract boolean
compare(A actual, E expected)
Returns whether or not theactual
value is said to correspond to theexpected
value for the purposes of this test.boolean
equals(@Nullable Object o)
Deprecated.Object.equals(Object)
is not supported.@Nullable String
formatDiff(A actual, E expected)
Returns aString
describing the difference between theactual
andexpected
values, if possible, ornull
if not.Correspondence<A,E>
formattingDiffsUsing(Correspondence.DiffFormatter<? super A,? super E> formatter)
Returns a new correspondence which is like this one, except that the given formatter may be used to format the difference between a pair of elements that do not correspond.static <A extends @Nullable Object,E extends @Nullable Object>
Correspondence<A,E>from(Correspondence.BinaryPredicate<A,E> predicate, String description)
Constructs aCorrespondence
that compares actual and expected elements using the given binary predicate.int
hashCode()
Deprecated.Object.hashCode()
is not supported.static Correspondence<Number,Number>
tolerance(double tolerance)
Returns aCorrespondence
betweenNumber
instances that considers instances to correspond (i.e.abstract String
toString()
Returns a description of the correspondence, suitable to fill the gap in a failure message of the form"<some actual element> is an element that ... <some expected element>"
.static <A extends @Nullable Object,E extends @Nullable Object>
Correspondence<A,E>transforming(Function<A,?> actualTransform, Function<E,?> expectedTransform, String description)
Constructs aCorrespondence
that compares elements by transforming the actual and the expected elements using the given functions and testing the transformed values for equality.static <A extends @Nullable Object,E extends @Nullable Object>
Correspondence<A,E>transforming(Function<A,? extends E> actualTransform, String description)
Constructs aCorrespondence
that compares elements by transforming the actual elements using the given function and testing for equality with the expected elements.
-
-
-
Method Detail
-
from
public static <A extends @Nullable Object,E extends @Nullable Object> Correspondence<A,E> from(Correspondence.BinaryPredicate<A,E> predicate, String description)
Constructs aCorrespondence
that compares actual and expected elements using the given binary predicate.The correspondence does not support formatting of diffs (see
formatDiff(A, E)
). You can add that behaviour by callingformattingDiffsUsing(com.google.common.truth.Correspondence.DiffFormatter<? super A, ? super E>)
.Note that, if the data you are asserting about contains nulls, your predicate may be invoked with null arguments. If this causes it to throw a
NullPointerException
, then your test will fail. (Seecompare(A, E)
for more detail on how exceptions are handled.) In particular, if your predicate is an instance method reference on the actual value (as in theString::contains
example below), your test will fail if it sees null actual values.Example using an instance method reference:
static final Correspondence<String, String> CONTAINS_SUBSTRING = Correspondence.from(String::contains, "contains");
Example using a static method reference:
class MyRecordTestHelper { static final Correspondence<MyRecord, MyRecord> EQUIVALENCE = Correspondence.from(MyRecordTestHelper::recordsEquivalent, "is equivalent to"); static boolean recordsEquivalent(MyRecord actual, MyRecord expected) { // code to check whether records should be considered equivalent for testing purposes } }
Example using a lambda:
static final Correspondence<Object, Class<?>> INSTANCE_OF = Correspondence.from((obj, clazz) -> clazz.isInstance(obj), "is an instance of");
- Parameters:
predicate
- aCorrespondence.BinaryPredicate
taking an actual and expected value (in that order) and returning whether the actual value corresponds to the expected value in some waydescription
- should fill the gap in a failure message of the form"not true that <some actual element> is an element that <description> <some expected element>"
, e.g."contains"
,"is an instance of"
, or"is equivalent to"
-
transforming
public static <A extends @Nullable Object,E extends @Nullable Object> Correspondence<A,E> transforming(Function<A,? extends E> actualTransform, String description)
Constructs aCorrespondence
that compares elements by transforming the actual elements using the given function and testing for equality with the expected elements. If the transformed actual element (i.e. the output of the given function) is null, it will correspond to a null expected element.The correspondence does not support formatting of diffs (see
formatDiff(A, E)
). You can add that behaviour by callingformattingDiffsUsing(com.google.common.truth.Correspondence.DiffFormatter<? super A, ? super E>)
.Note that, if you the data you are asserting about contains null actual values, your function may be invoked with a null argument. If this causes it to throw a
NullPointerException
, then your test will fail. (Seecompare(A, E)
for more detail on how exceptions are handled.) In particular, this applies if your function is an instance method reference on the actual value (as in the example below). If you want a null actual element to correspond to a null expected element, you must ensure that your function transforms a null input to a null output.Example:
This can be used as follows:static final Correspondence<MyRecord, Integer> HAS_ID = Correspondence.transforming(MyRecord::getId, "has an ID of");
assertThat(myRecords).comparingElementsUsing(HAS_ID).containsExactly(123, 456, 789);
- Parameters:
actualTransform
- aFunction
taking an actual value and returning a new value which will be compared with an expected value to determine whether they corresponddescription
- should fill the gap in a failure message of the form"not true that <some actual element> is an element that <description> <some expected element>"
, e.g."has an ID of"
-
transforming
public static <A extends @Nullable Object,E extends @Nullable Object> Correspondence<A,E> transforming(Function<A,?> actualTransform, Function<E,?> expectedTransform, String description)
Constructs aCorrespondence
that compares elements by transforming the actual and the expected elements using the given functions and testing the transformed values for equality. If an actual element is transformed to null, it will correspond to an expected element that is also transformed to null.The correspondence does not support formatting of diffs (see
formatDiff(A, E)
). You can add that behaviour by callingformattingDiffsUsing(com.google.common.truth.Correspondence.DiffFormatter<? super A, ? super E>)
.Note that, if you the data you are asserting about contains null actual or expected values, the appropriate function may be invoked with a null argument. If this causes it to throw a
NullPointerException
, then your test will fail. (Seecompare(A, E)
for more detail on how exceptions are handled.) In particular, this applies if your function is an instance method reference on the actual or expected value (as in the example below). If you want a null actual element to correspond to a null expected element, you must ensure that your functions both transform a null input to a null output.If you want to apply the same function to both the actual and expected elements, just provide the same argument twice.
Example:
This can be used as follows:static final Correspondence<MyRequest, MyResponse> SAME_IDS = Correspondence.transforming(MyRequest::getId, MyResponse::getId, "has the same ID as");
assertThat(myResponses).comparingElementsUsing(SAME_IDS).containsExactlyElementsIn(myRequests);
- Parameters:
actualTransform
- aFunction
taking an actual value and returning a new value which will be compared with a transformed expected value to determine whether they correspondexpectedTransform
- aFunction
taking an expected value and returning a new value which will be compared with a transformed actual valuedescription
- should fill the gap in a failure message of the form"not true that <some actual element> is an element that <description> <some expected element>"
, e.g."has the same ID as"
-
tolerance
public static Correspondence<Number,Number> tolerance(double tolerance)
Returns aCorrespondence
betweenNumber
instances that considers instances to correspond (i.e.compare(Object, Object)
returnstrue
) if the double values of each instance (i.e. the result of callingNumber.doubleValue()
on them) are finite values withintolerance
of each other.- It does not consider instances to correspond if either value is infinite or NaN.
- The conversion to double may result in a loss of precision for some numeric types.
- The
compare(Object, Object)
method throws aNullPointerException
if eitherNumber
instance is null.
- Parameters:
tolerance
- an inclusive upper bound on the difference between the double values of the twoNumber
instances, which must be a non-negative finite value, i.e. notDouble.NaN
,Double.POSITIVE_INFINITY
, or negative, including-0.0
-
formattingDiffsUsing
public Correspondence<A,E> formattingDiffsUsing(Correspondence.DiffFormatter<? super A,? super E> formatter)
Returns a new correspondence which is like this one, except that the given formatter may be used to format the difference between a pair of elements that do not correspond.Note that, if you the data you are asserting about contains null actual or expected values, the formatter may be invoked with a null argument. If this causes it to throw a
NullPointerException
, that will be taken to indicate that the values cannot be diffed. (SeeformatDiff(A, E)
for more detail on how exceptions are handled.) If you think null values are likely, it is slightly cleaner to have the formatter return null in that case instead of throwing.Example:
class MyRecordTestHelper { static final Correspondence<MyRecord, MyRecord> EQUIVALENCE = Correspondence.from(MyRecordTestHelper::recordsEquivalent, "is equivalent to") .formattingDiffsUsing(MyRecordTestHelper::formatRecordDiff); static boolean recordsEquivalent(MyRecord actual, MyRecord expected) { // code to check whether records should be considered equivalent for testing purposes } static String formatRecordDiff(MyRecord actual, MyRecord expected) { // code to format the diff between the records } }
-
compare
public abstract boolean compare(A actual, E expected)
Returns whether or not theactual
value is said to correspond to theexpected
value for the purposes of this test.Exception handling
Throwing a
RuntimeException
from this method indicates that thisCorrespondence
cannot compare the given values. Any assertion which encounters such an exception during the course of evaluating its condition must not pass. However, an assertion is not required to invoke this method for every pair of values in its input just in order to check for exceptions, if it is able to evaluate its condition without doing so.Conventions for handling exceptions
(N.B. This section is only really of interest when implementing assertion methods that call
compare(A, E)
, not to users making such assertions in their tests.)The only requirement on an assertion is that, if it encounters an exception from this method, it must not pass. The simplest implementation choice is simply to allow the exception to propagate. However, it is normally more helpful to catch the exception and instead fail with a message which includes more information about the assertion in progress and the nature of the failure.
By convention, an assertion may catch and store the exception and continue evaluating the condition as if the method had returned false instead of throwing. If the assertion's condition does not hold with this alternative behaviour, it may choose to fail with a message that gives details about how the condition does not hold, additionally mentioning that assertions were encountered and giving details about one of the stored exceptions. (See the first example below.) If the assertion's condition does hold with this alternative behaviour, the requirement that the assertion must not pass still applies, so it should fail with a message giving details about one of the stored exceptions. (See the second and third examples below.)
This behaviour is only a convention and should only be implemented when it makes sense to do so. In particular, in an assertion that has multiple stages, it may be better to only continue evaluation to the end of the current stage, and fail citing a stored exception at the end of the stage, rather than accumulating exceptions through the multiple stages.
Examples of exception handling
Suppose that we have the correspondence
whosestatic final Correspondence<String, String> CASE_INSENSITIVE_EQUALITY = Correspondence.from(String::equalsIgnoreCase, "equals ignoring case"
}compare
method throwsNullPointerException
if the actual value is null. The assertion
may fail saying that the actual iterable contains unexpected valuesassertThat(asList(null, "xyz", "abc", "def")) .comparingElementsUsing(CASE_INSENSITIVE_EQUALITY) .containsExactly("ABC", "DEF", "GHI", "JKL");
null
andxyz
and is missing values corresponding toGHI
andJKL
, which is what it would do if thecompare
method returned false instead of throwing, and additionally mention the exception. (This is more helpful than allowing theNullPointerException
to propagate to the caller, or than failing with only a description of the exception.)However, the assertions
andassertThat(asList(null, "xyz", "abc", "def")) .comparingElementsUsing(CASE_INSENSITIVE_EQUALITY) .doesNotContain("MNO");
must both fail citing the exception, even though they would pass if theassertThat(asList(null, "xyz", "abc", "def")) .comparingElementsUsing(CASE_INSENSITIVE_EQUALITY) .doesNotContain(null);
compare
method returned false. (Note that, in the latter case at least, it is likely that the test author's intention was not for the test to pass with these values.)
-
formatDiff
public @Nullable String formatDiff(A actual, E expected)
Returns aString
describing the difference between theactual
andexpected
values, if possible, ornull
if not.The implementation on the
Correspondence
base class always returnsnull
. To enable diffing, useformattingDiffsUsing(com.google.common.truth.Correspondence.DiffFormatter<? super A, ? super E>)
(or override this method in a subclass, but factory methods are recommended over subclassing).Assertions should only invoke this with parameters for which
compare(A, E)
returnsfalse
.If this throws an exception, that implies that it is not possible to describe the diffs. An assertion will normally only call this method if it has established that its condition does not hold: good practice dictates that, if this method throws, the assertion should catch the exception and continue to describe the original failure as if this method had returned null, mentioning the failure from this method as additional information.
-
toString
public abstract String toString()
Returns a description of the correspondence, suitable to fill the gap in a failure message of the form"<some actual element> is an element that ... <some expected element>"
. Note that this is a fragment of a verb phrase which takes a singular subject.Example 1: For a
Correspondence<String, Integer>
that tests whether the actual string parses to the expected integer, this would return"parses to"
to result in a failure message of the form"<some actual string> is an element that parses to <some expected integer>"
.Example 2: For the
Correspondence<Number, Number>
returns bytolerance(double)
this returns"is a finite number within " + tolerance + " of"
to result in a failure message of the form"<some actual number> is an element that is a finite number within 0.0001 of <some expected number>"
.
-
equals
@Deprecated public final boolean equals(@Nullable Object o)
Deprecated.Object.equals(Object)
is not supported. If you meant to compare objects using thisCorrespondence
, usecompare(A, E)
.- Overrides:
equals
in classObject
- Throws:
UnsupportedOperationException
- always
-
hashCode
@Deprecated public final int hashCode()
Deprecated.Object.hashCode()
is not supported.- Overrides:
hashCode
in classObject
- Throws:
UnsupportedOperationException
- always
-
-