public abstract class Correspondence<A,E> extends Object
A
corresponds in some way to an instance of type
E
for the purposes of a test assertion. For example, the implementation returned by the
tolerance(double)
factory method implements approximate equality between numeric values,
with values being said to correspond if the difference between them is does not exceed some fixed
tolerance. The instances of type A
are typically actual values from a collection returned
by the code under test; the instances of type E
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
and
expected
, multiple invocations of compare(actual, expected)
must consistently
return true
or consistently return false
(provided that neither value is
modified). Although A
and E
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 using
formattingDiffsUsing(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>)
, or MultimapSubject.comparingValuesUsing(com.google.common.truth.Correspondence<? super A, ? super E>)
.
Modifier and Type | Class and Description |
---|---|
static interface |
Correspondence.BinaryPredicate<A,E>
A functional interface for a binary predicate, to be used to test whether a pair of objects of
types
A and E satisfy some condition. |
static interface |
Correspondence.DiffFormatter<A,E>
A functional interface to be used format the diff between a pair of objects of types
A
and E . |
Modifier | Constructor and Description |
---|---|
protected |
Correspondence()
Deprecated.
Construct an instance with the static factory methods instead. The most mechanical
migration is usually to
from(com.google.common.truth.Correspondence.BinaryPredicate<A, E>, java.lang.String) . |
Modifier and Type | Method and Description |
---|---|
abstract boolean |
compare(A actual,
E expected)
Returns whether or not the
actual value is said to correspond to the expected
value for the purposes of this test. |
boolean |
equals(Object o)
Deprecated.
Object.equals(Object) is not supported. If you meant to compare objects
using this Correspondence , use compare(A, E) . |
String |
formatDiff(A actual,
E expected)
Returns a
String describing the difference between the actual and expected values, if possible, or null 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,E> Correspondence<A,E> |
from(Correspondence.BinaryPredicate<A,E> predicate,
String description)
Constructs a
Correspondence 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 a
Correspondence between Number 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 {@code "
|
static <A,E> Correspondence<A,E> |
transforming(Function<A,?> actualTransform,
Function<E,?> expectedTransform,
String description)
Constructs a
Correspondence that compares elements by transforming the actual and the
expected elements using the given functions and testing the transformed values for equality. |
static <A,E> Correspondence<A,E> |
transforming(Function<A,? extends E> actualTransform,
String description)
Constructs a
Correspondence that compares elements by transforming the actual elements
using the given function and testing for equality with the expected elements. |
@Deprecated protected Correspondence()
from(com.google.common.truth.Correspondence.BinaryPredicate<A, E>, java.lang.String)
.public static <A,E> Correspondence<A,E> from(Correspondence.BinaryPredicate<A,E> predicate, String description)
Correspondence
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 calling formattingDiffsUsing(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. (See compare(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 the
String::startsWith
example below), your test will fail if it sees null actual values.
Example using an instance method reference:
static final Correspondence<String, String> STRING_PREFIX_EQUALITY =
Correspondence.from(String::startsWith, "starts with");
Example using a static method reference:
class MyRecordTestHelper {
static final Correspondence<MyRecord, MyRecord> EQUIVALENCE =
Correspondence.from(MyRecordTestHelper::recordsEquivalent, "is equivalent to");
static boolean recordsEquivalent(@Nullable MyRecord actual, @Nullable 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");
predicate
- a Correspondence.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.
"starts with"
, "is an instance of"
, or "is equivalent to"
public static <A,E> Correspondence<A,E> transforming(Function<A,? extends E> actualTransform, String description)
Correspondence
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 calling formattingDiffsUsing(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. (See compare(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:
static final Correspondence<MyRecord, Integer> HAS_ID =
Correspondence.transforming(MyRecord::getId, "has an ID of");
This can be used as follows:
assertThat(myRecords).comparingElementsUsing(HAS_ID).containsExactly(123, 456, 789);
actualTransform
- a Function
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"
public static <A,E> Correspondence<A,E> transforming(Function<A,?> actualTransform, Function<E,?> expectedTransform, String description)
Correspondence
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 calling formattingDiffsUsing(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. (See compare(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:
static final Correspondence<MyRequest, MyResponse> SAME_IDS =
Correspondence.transforming(MyRequest::getId, MyResponse::getId, "has the same ID as");
This can be used as follows:
assertThat(myResponses).comparingElementsUsing(SAME_IDS).containsExactlyElementsIn(myRequests);
actualTransform
- a Function
taking an actual value and returning a new value
which will be compared with a transformed expected value to determine whether they
correspondexpectedTransform
- a Function
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"
public static Correspondence<Number,Number> tolerance(double tolerance)
Correspondence
between Number
instances that considers instances to
correspond (i.e. compare(Object, Object)
returns true
) if the
double values of each instance (i.e. the result of calling Number.doubleValue()
on
them) are finite values within tolerance
of each other.
compare(Object, Object)
method throws a NullPointerException
if either Number
instance is null.
tolerance
- an inclusive upper bound on the difference between the double values of the
two Number
instances, which must be a non-negative finite value, i.e. not Double.NaN
, Double.POSITIVE_INFINITY
, or negative, including -0.0
public Correspondence<A,E> formattingDiffsUsing(Correspondence.DiffFormatter<? super A,? super E> formatter)
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. (See
formatDiff(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(@Nullable MyRecord actual, @Nullable MyRecord expected) {
// code to check whether records should be considered equivalent for testing purposes
}
static String formatRecordDiff(@Nullable MyRecord actual, @Nullable MyRecord expected) {
// code to format the diff between the records
}
}
public abstract boolean compare(@NullableDecl A actual, @NullableDecl E expected)
actual
value is said to correspond to the expected
value for the purposes of this test.
Throwing a RuntimeException
from this method indicates that this Correspondence
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.
(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.
Suppose that we have the correspondence
static final Correspondence<String, String> CASE_INSENSITIVE_EQUALITY =
Correspondence.from(String::equalsIgnoreCase, "equals ignoring case"
}
whose compare
method throws NullPointerException
if the actual value is null.
The assertion
assertThat(asList(null, "xyz", "abc", "def"))
.comparingElementsUsing(CASE_INSENSITIVE_EQUALITY)
.containsExactly("ABC", "DEF", "GHI", "JKL");
may fail saying that the actual iterable contains unexpected values null
and xyz
and is missing values corresponding to GHI
and JKL
, which is what it would
do if the compare
method returned false instead of throwing, and additionally mention
the exception. (This is more helpful than allowing the NullPointerException
to
propagate to the caller, or than failing with only a description of the exception.)
However, the assertions
assertThat(asList(null, "xyz", "abc", "def"))
.comparingElementsUsing(CASE_INSENSITIVE_EQUALITY)
.doesNotContain("MNO");
and
assertThat(asList(null, "xyz", "abc", "def"))
.comparingElementsUsing(CASE_INSENSITIVE_EQUALITY)
.doesNotContain(null);
must both fail citing the exception, even though they would pass if the 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.)@NullableDecl public String formatDiff(@NullableDecl A actual, @NullableDecl E expected)
String
describing the difference between the actual
and expected
values, if possible, or null
if not.
The implementation on the Correspondence
base class always returns null
. To
enable diffing, use formattingDiffsUsing(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)
returns false
.
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.
public abstract String toString()
"<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 by tolerance(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>"
.
@Deprecated public final boolean equals(@NullableDecl Object o)
Object.equals(Object)
is not supported. If you meant to compare objects
using this Correspondence
, use compare(A, E)
.equals
in class Object
UnsupportedOperationException
- always@Deprecated public final int hashCode()
Object.hashCode()
is not supported.hashCode
in class Object
UnsupportedOperationException
- alwaysCopyright © 2019. All rights reserved.