![](/img/trans.png)
[英]How to assert two list values with contains, but not a exact equal comparison in java
[英]How to test if a generic list contains the exact subcollection of a subtype in Java?
我有一个抽象类AbstractService和几个扩展该抽象类的类:
然后,我有一个ServiceFactory,它根据我传递的参数返回带有一些服务的通用列表:
public class ServiceFactory {
public List<? extends AbstractService> getServices(final MyParameter param) {
// Service is an interface implemented by AbstractService
List<Service> services = new ArrayList<>();
for (Foo foo : param.getFoos()) {
services.add(new AService(foo.getBar()));
}
// creates the rest of the services
return services;
}
}
在我的UnitTest中,我想验证我的服务列表是否恰好包含3个AService子类型。 我现在这样做的方式是:
@Test
public void serviceFactoryShouldReturnAServiceForEachFoo() {
// I'm mocking MyParameter and Foo here
Mockito.when(param.getFoos()).thenReturn(Arrays.asList(foo, foo, foo);
AService aservice = new AService(foo);
List<AService> expectedServices = Arrays.asList(aservice, aservice, aservice);
List<? extends AbstractService> actualServices = serviceFactory.getServices();
assertTrue(CollectionUtils.isSubCollection(expectedServices, actualServices));
}
当ActualServices包含的服务少于3个时,测试将正确失败。 此解决方案的唯一问题是,如果actualServices包含三个以上的AService,则测试通过...
有没有一种方法可以做到这一点,或者我应该自己使用循环来实现?
您可以使用hamcrest Matchers。
hamcrest-library包含用于检查收集/可迭代内容的匹配器。
我希望以下示例可以轻松地与您的szenario匹配
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.mock;
import static org.hamcrest.Matchers.containsInAnyOrder;
import java.util.ArrayList;
import java.util.Collection;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.junit.Test;
public class ServiceFactoryTest
{
@Test
public void serviceFactoryShouldReturnAServiceForEachFoo()
{
Foo foo = mock( Foo.class );
Service service = new AService( foo );
Service[] expected = { service, service, service };
Service[] tooFew = { service, service };
Service[] tooMany = { service, service, service, service };
ServiceFactory factory = new ServiceFactory();
assertThat( factory.createServices( foo, foo, foo ), containsInAnyOrder( expected ) );
assertThat( factory.createServices( foo, foo, foo ), not( containsInAnyOrder( tooFew ) ) );
assertThat( factory.createServices( foo, foo, foo ), not( containsInAnyOrder( tooMany ) ) );
}
interface Foo
{}
interface Service
{}
class AService implements Service
{
Foo foo;
public AService( Foo foo )
{
this.foo = foo;
}
@Override
public boolean equals( Object that )
{
return EqualsBuilder.reflectionEquals( this, that );
}
}
class ServiceFactory
{
Collection<? extends Service> createServices( Foo... foos )
{
Collection<Service> list = new ArrayList<>();
for ( Foo foo : foos )
{
list.add( new AService( foo ) );
}
return list;
}
}
}
可以肯定的是,AService的子类型是AService的实例,并且返回true的条件是正确的。
甚至没有使用循环来实现它的好方法,而且很大程度上取决于执行上下文,从不同的类加载器加载的“相同”类是“不同的”。
我会退后一步,考虑您要验证的AService的属性,是否应该在AbstractService中定义该属性? 并且,最后使用该属性来验证结果。
非常感谢Max Fichtelmann向我指出正确的方向!
我最终开始使用Fest assert ,但是使用Hamcrest可能可以达到相同的结果。
我创建了一个自定义匹配器assertEvery
,比较列表大小:
public class ServiceAssert extends AbstractAssert<ServiceAssert, List<Service>> {
public ServiceAssert(List<Service> actual) {
super(actual, ServiceAssert.class);
}
// it's usually assertThat, but it conflicts with the List<T> assertions
public static ServiceAssert assertThatMy(List<Service> actual) {
return new ServiceAssert(actual);
}
public ServiceAssert containsEvery(List<? extends Service> expectedServices) {
Integer listSize = 0;
isNotNull();
if (expectedServices == null || expectedServices.isEmpty()) {
throw new AssertionError("Do not use this method for an empty or null list of services, use doesNotContain instead.");
}
Class<? extends Service> serviceClass = expectedServices.get(0).getClass();
for (Service f : actual) {
if (f.getClass().equals(serviceClass)) {
listSize++;
}
}
if (listSize != expectedServices.size()) {
throw new AssertionError("expected " + expectedServices.size() + " " + serviceClass.getSimpleName() + " but was " + listSize + ".");
}
return this;
}
}
现在,我可以将其与import static myassertions.impl.ServiceAssert.assertThatMy;
一起使用import static myassertions.impl.ServiceAssert.assertThatMy;
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.