比较 Set 中项目的 Mockito 匹配器,而不是 Set 引用本身
Mockito matcher that compares items in Set, not the Set reference itself
when(validator.isValid(Sets.newHashSet("valid"))).thenReturn(true);
当调用 validator.isValid(set)
时,它 returns false。这是因为验证器实现创建了一个新的集合,它与传递的集合不同(引用不同)——两个集合中的项目是相同的。
我需要 return true 如果集合包含相同的项目而不考虑集合实例。
类似于org.mockito.Matchers
的内容:
public static <T> Set<T> anySetOf(Class<T> clazz) {
return (Set) reportMatcher(Any.ANY).returnSet();
}
除了我会传递实例而不是 Class<T>.class
。
verify
也一样:
verify(validator, times(1)).isValid(Sets.newHashSet("valid"));
有这样的匹配器吗?
显然 JB Nizet 是对的。不需要特定的匹配器。
我试过使用我自己的匹配器,然后在移除后它也起作用了:
public static class SetItemMatcher extends ArgumentMatcher<Set<String>> {
public static Set<String> setOf(Set<String> items) {
return argThat(new SetItemMatcher(items));
}
private final Set<String> expected;
public SetItemMatcher(Set<String> expected) {
this.expected = expected;
}
@Override
public boolean matches(Object argument) {
Set<?> actual = (Set<?>) argument;
return actual.size() == expected.size() && containsAllItems(actual);
}
private boolean containsAllItems(Set<?> actual) {
for (Object o : actual) {
if (!expected.contains(o)) {
return false;
}
}
return true;
}
}
虽然 Felix 的回答绝对正确,但我稍微修改了一下以涵盖更多内容 use-cases:
- 使用任何集合,而不仅仅是集合。
- 添加了实用程序方法以仅基于一项或另一项创建列表或集合list/set
public class CollectionItemMatcher<T extends Collection> implements ArgumentMatcher<T> {
public static Set setOf(Object oneItem) {
return setOf(Sets.newHashSet(oneItem));
}
public static Set setOf(Collection items) {
return ArgumentMatchers.argThat(new CollectionItemMatcher<Set>(Sets.newHashSet(items)));
}
public static List listOf(Object oneItem) {
return listOf(Lists.newArrayList(oneItem));
}
public static List listOf(Collection items) {
return ArgumentMatchers.argThat(new CollectionItemMatcher<List>(Lists.newArrayList(items)));
}
private final T expected;
public CollectionItemMatcher(T expected) {
this.expected = expected;
}
@Override
public boolean matches(T actual) {
return actual.size() == expected.size() && containsAllItems(actual);
}
private boolean containsAllItems(T actual) {
for (Object o : actual) {
if (!expected.contains(o)) {
return false;
}
}
return true;
}
}
那么你可以这样做:
verify(validator, times(1)).isValid(CollectionItemMatcher.setOf("valid"));
when(validator.isValid(Sets.newHashSet("valid"))).thenReturn(true);
当调用 validator.isValid(set)
时,它 returns false。这是因为验证器实现创建了一个新的集合,它与传递的集合不同(引用不同)——两个集合中的项目是相同的。
我需要 return true 如果集合包含相同的项目而不考虑集合实例。
类似于org.mockito.Matchers
的内容:
public static <T> Set<T> anySetOf(Class<T> clazz) {
return (Set) reportMatcher(Any.ANY).returnSet();
}
除了我会传递实例而不是 Class<T>.class
。
verify
也一样:
verify(validator, times(1)).isValid(Sets.newHashSet("valid"));
有这样的匹配器吗?
显然 JB Nizet 是对的。不需要特定的匹配器。
我试过使用我自己的匹配器,然后在移除后它也起作用了:
public static class SetItemMatcher extends ArgumentMatcher<Set<String>> {
public static Set<String> setOf(Set<String> items) {
return argThat(new SetItemMatcher(items));
}
private final Set<String> expected;
public SetItemMatcher(Set<String> expected) {
this.expected = expected;
}
@Override
public boolean matches(Object argument) {
Set<?> actual = (Set<?>) argument;
return actual.size() == expected.size() && containsAllItems(actual);
}
private boolean containsAllItems(Set<?> actual) {
for (Object o : actual) {
if (!expected.contains(o)) {
return false;
}
}
return true;
}
}
虽然 Felix 的回答绝对正确,但我稍微修改了一下以涵盖更多内容 use-cases:
- 使用任何集合,而不仅仅是集合。
- 添加了实用程序方法以仅基于一项或另一项创建列表或集合list/set
public class CollectionItemMatcher<T extends Collection> implements ArgumentMatcher<T> {
public static Set setOf(Object oneItem) {
return setOf(Sets.newHashSet(oneItem));
}
public static Set setOf(Collection items) {
return ArgumentMatchers.argThat(new CollectionItemMatcher<Set>(Sets.newHashSet(items)));
}
public static List listOf(Object oneItem) {
return listOf(Lists.newArrayList(oneItem));
}
public static List listOf(Collection items) {
return ArgumentMatchers.argThat(new CollectionItemMatcher<List>(Lists.newArrayList(items)));
}
private final T expected;
public CollectionItemMatcher(T expected) {
this.expected = expected;
}
@Override
public boolean matches(T actual) {
return actual.size() == expected.size() && containsAllItems(actual);
}
private boolean containsAllItems(T actual) {
for (Object o : actual) {
if (!expected.contains(o)) {
return false;
}
}
return true;
}
}
那么你可以这样做:
verify(validator, times(1)).isValid(CollectionItemMatcher.setOf("valid"));