作者:农大军乐团_697 | 2023-09-08 19:25
我想测试一个列表包含一个对象的实例。
例如,对于一个实例:
assertThat(mylist).containsExactly(Matchers.any(ExpectedType.class));
从test返回的数组obj
确实包含instance的一个对象ExpectedType
。但是我的测试失败了:
java.lang.AssertionError:<[ExpectedType @ 7c781c42]>完全包含<[ExpectedType的实例]>是不正确的。它缺少<[ExpectedType的实例]>,并且具有意外的项目<[ExpectedType @ 7c781c42]>
如何编写此测试?
1> heenenee..: 您正在尝试编写一个测试,以List
使用Hamcrest 和 Truth 来查看一个类是否恰好包含一个特定类的实例。相反,您应该使用 Hamcrest 或 Truth 编写此测试。Hamcrest和Truth都是用于使测试更具表现力的库,每个库都有自己的特定用法,样式和语法。如果愿意,可以在测试中将它们并排使用,但是在执行过程中将它们的方法链接在一起是行不通的。(也许您会感到困惑,因为这两个库都可以具有以assertThat
?。)因此,对于此特定测试,您需要选择其中一个并进行处理。
但是,这两个库都缺少检查a List
是否具有一个且只有一个 的内置功能。 满足条件的。因此,对于任何一个库,您都有两个选择:要么可以对列表进行一些预处理,以便可以使用内置的断言,要么可以扩展库的语言以提供此功能。
下面是一个示例类,演示了两个库的两个选项:
import com.google.common.collect.FluentIterable;
import com.google.common.truth.*;
import org.hamcrest.*;
import org.junit.Test;
import java.util.*;
import static com.google.common.truth.Truth.assertAbout;
import static com.google.common.truth.Truth.assert_;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
public class ExactlyOneInstanceTest {
List myList = Arrays.asList("", 3, 'A', new Object());
@Test
public void hamcrestBuiltInTestExactlyOneInstance() {
long theNumberOfStringsInMyList = myList.stream().filter(o -> o instanceof String).count();
assertThat(theNumberOfStringsInMyList, equalTo(1L));
}
@Test
public void hamcrestExtendedTestExactlyOneInstance() {
assertThat(myList, HasExactlyOne.itemThat(is(instanceOf(String.class))));
}
@Test
public void truthBuiltInTestExactlyOneInstance() {
long theNumberOfStringsInMyList = myList.stream().filter(o -> o instanceof String).count();
// can't static import Truth.assertThat because of name clash,
// but we can use this alternative form
assert_().that(theNumberOfStringsInMyList).isEqualTo(1);
}
@Test
public void truthExtendedTestExactlyOneInstance() {
assertAbout(iterable()).that(myList).containsExactlyOneInstanceOf(String.class);
}
// Hamcrest custom matcher
static class HasExactlyOne extends TypeSafeDiagnosingMatcher> {
Matcher super T> elementMatcher;
HasExactlyOne(Matcher super T> elementMatcher) {
this.elementMatcher = elementMatcher;
}
@Factory
public static Matcher> itemThat(Matcher super T> itemMatcher) {
return new HasExactlyOne<>(itemMatcher);
}
@Override
public void describeTo(Description description) {
description
.appendText("a collection containing exactly one item that ")
.appendDescriptionOf(elementMatcher);
}
@Override
protected boolean matchesSafely(Iterable super T> item, Description mismatchDescription) {
return FluentIterable.from(item).filter(o -> elementMatcher.matches(o)).size() == 1;
}
}
// Truth custom extension
static SubjectFactory, Iterable> iterable() {
return new SubjectFactory, Iterable>() {
@Override
public ExtendedIterableSubject getSubject(FailureStrategy fs, Iterable target) {
return new ExtendedIterableSubject<>(fs, target);
}
};
}
static class ExtendedIterableSubject extends IterableSubject, T, Iterable> {
ExtendedIterableSubject(FailureStrategy failureStrategy, Iterable list) {
super(failureStrategy, list);
}
void containsExactlyOneInstanceOf(Class> clazz) {
if (FluentIterable.from(getSubject()).filter(clazz).size() != 1) {
fail("contains exactly one instance of", clazz.getName());
}
}
}
}
尝试运行并查看该类,并使用最适合您的方式。在编写将来的测试时,只需尝试使用您可以使用的内置断言,并尝试使@Test
方法及其断言的意图立即可读。如果看到您多次编写相同的代码,或者测试方法不是那么容易阅读,则可以重构和/或扩展所用库的语言。重复进行,直到所有内容都经过测试并且所有测试都易于理解为止。请享用!