assertTrue()/assertFalse() : to use only to assert boolean result returned
assertTrue(Iterables.elementsEqual(argumentComponents,
returnedComponents));
You want to use Assert.assertTrue()
or Assert.assertFalse()
as the method under test returns a boolean
value.
As the method returns a specific thing such as a List
that should contain some expected elements, asserting with assertTrue()
in this way : Assert.assertTrue(myActualList.containsAll(myExpectedList)
is an anti pattern.
It makes the assertion easy to write but as the test fails, it also makes it hard to debug because the test runner will only say to you something like :
expected true
but actual is false
Assert.assertEquals(Object, Object)
in JUnit4 or Assertions.assertIterableEquals(Iterable, Iterable)
in JUnit 5 : to use only as both equals()
and toString()
are overrided for the classes (and deeply) of the compared objects
It matters because the equality test in the assertion relies on equals()
and the test failure message relies on toString()
of the compared objects.
As String
overrides both equals()
and toString()
, it is perfectly valid to assert the List<String>
with assertEquals(Object,Object)
.
And about this matter : you have to override equals()
in a class because it makes sense in terms of object equality, not only to make assertions easier in a test with JUnit.
To make assertions easier you have other ways (that you can see in the next points of the answer).
Is Guava a way to perform/build unit test assertions ?
Is Google Guava Iterables.elementsEqual() the best way, provided I have the library in my build path, to compare those two lists?
No it is not. Guava is not an library to write unit test assertions.
You don't need it to write most (all I think) of unit tests.
What's the canonical way to compare lists for unit tests?
As a good practice I favor assertion/matcher libraries.
I cannot encourage JUnit to perform specific assertions because this provides really too few and limited features : it performs only an assertion with a deep equals.
Sometimes you want to allow any order in the elements, sometimes you want to allow that any elements of the expected match with the actual, and so for...
So using a unit test assertion/matcher library such as Hamcrest or AssertJ is the correct way.
The actual answer provides a Hamcrest solution. Here is a AssertJ solution.
org.assertj.core.api.ListAssert.containsExactly()
is what you need : it verifies that the actual group contains exactly the given values and nothing else, in order as stated :
Verifies that the actual group contains exactly the given values and
nothing else, in order.
Your test could look like :
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
@Test
void ofComponent_AssertJ() throws Exception {
MyObject myObject = MyObject.ofComponents("One", "Two", "Three");
Assertions.assertThat(myObject.getComponents())
.containsExactly("One", "Two", "Three");
}
A AssertJ good point is that declaring a List
as expected is needless : it makes the assertion straighter and the code more readable :
Assertions.assertThat(myObject.getComponents())
.containsExactly("One", "Two", "Three");
And if the test fails :
// Fail : Three was not expected
Assertions.assertThat(myObject.getComponents())
.containsExactly("One", "Two");
you get a very clear message such as :
java.lang.AssertionError:
Expecting:
<["One", "Two", "Three"]>
to contain exactly (and in same order):
<["One", "Two"]>
but some elements were not expected:
<["Three"]>
Assertion/matcher libraries are a must because these will really further
假设MyObject
不存储String
s 而是Foo
s 实例,例如:
public class MyFooObject {
private List<Foo> values;
@SafeVarargs
public static MyFooObject ofComponents(Foo... values) {
// ...
}
public List<Foo> getComponents(){
return new ArrayList<>(values);
}
}
这是一个非常普遍的需求。使用 AssertJ,断言仍然很容易编写。更好的是,您可以断言列表内容是相等的,即使元素的类没有覆盖equals()/hashCode()
,而 JUnit 方式要求:
import org.assertj.core.api.Assertions;
import static org.assertj.core.groups.Tuple.tuple;
import org.junit.jupiter.api.Test;
@Test
void ofComponent() throws Exception {
MyFooObject myObject = MyFooObject.ofComponents(new Foo(1, "One"), new Foo(2, "Two"), new Foo(3, "Three"));
Assertions.assertThat(myObject.getComponents())
.extracting(Foo::getId, Foo::getName)
.containsExactly(tuple(1, "One"),
tuple(2, "Two"),
tuple(3, "Three"));
}