繁体   English   中英

使用模拟异常测试自定义谓词由于不正确的模拟而失败 class

[英]Testing custom predicate using mocked Exception failing due to incorrect Mock class

我在下面创建了一个自定义Predicate并想使用mockito对其进行测试。 我正在创建特定异常类的模拟,因为它们没有公共构造函数。 运行测试后断言失败,因为predicate返回false而不是true 在打印模拟异常的class时,它有WebClientResponseException$ServiceUnavailable$MockitoMock$54675 。似乎没有正确识别模拟。 我在这里做错了什么吗?

谓词测试

@ExtendsWith(MockitoExtention.class)
class PredicateTest{

@InjectMocks
CustomPredicate customPredicate;



@Test
public void testPredicate(){

final ServiceUnavailable serviceUnavailable = mock(ServiceUnAvailable.class);

assertTrue(customPredicate.test(serviceUnavailable))
    
}  
}

自定义谓词

CustomPredicate implements Predicate<Throwable>{

private static final List<Class<?>> Exceptions= Arrays.asList(WebClientResponseException.ServiceUnavailable.class);

private static final Predicate<? super Throwable> ClassToControl= throwable -> Exception.contain(throwable.getClass());


@Override
public boolean test(Throwable t){

return ExceptionUtils.getThrowableList(t).stream().anyMatch(ClassToControl);

}


}

实际上问题出在mock(ServiceUnAvailable.class) - 当你以这种方式创建一个 object 时,它将有一个 class ServiceUnAvailable$MockitoMock ,而不是ServiceUnAvailable.class ,这意味着你的下一个检查填充失败:

Predicate<? super Throwable> ClassToControl= throwable -> Exception.contain(throwable.getClass());

因为Exceptions列表不包含元素ServiceUnAvailable$MockitoMock


为了以这种方式测试异常,我会建议下一个修复(我稍微更改了代码,但我希望这个想法很清楚):

谓词:

public class CustomPredicate implements Predicate<Throwable> {
    private final List<Class<?>> exceptions;
    private final Predicate<? super Throwable> classToControl;

    public CustomPredicate(Class<?>... exceptions) {
        this(Arrays.asList(exceptions));
    }

    public CustomPredicate(List<Class<?>> exceptions) {
        this.exceptions = exceptions;
        this.classToControl = throwable -> this.exceptions.contains(throwable.getClass());
    }

    @Override
    public boolean test(final Throwable throwable) {
        return ExceptionUtils.getThrowableList(throwable).stream()
            .anyMatch(classToControl);
    }
}

测试:

public class PredicateTest {
    @Test
    public void testPredicate() {
        final IllegalStateException serviceUnavailable = Mockito.mock(IllegalStateException.class);
        CustomPredicate customPredicate = new CustomPredicate(serviceUnavailable.getClass());
        assertTrue(customPredicate.test(serviceUnavailable));
    }
}

@VolodyaLombrozo 正确地确定了问题的根本原因:

var serviceUnavailableMock = mock(ServiceUnavailable.class);
System.out.println(serviceUnavailableMock.getClass());
System.out.println(serviceUnavailableMock.getClass() == ServiceUnavailable.class);
System.out.println(serviceUnavailableMock instanceof ServiceUnavailable);

// class org.example.ServiceUnavailable$MockitoMock$X21NGyAU
// false
// true

在他的回答之上,我想建议更多选项来更改您的代码:

让我们重构 CustomPredicate:

  • test() 将 wraps 输入转换为 1 元素列表,将其转换为 stream,并使用 anyMatch 运行测试。 这是令人困惑和不必要的。
public class CustomPredicate implements Predicate<Throwable> {
    private static final List<Class<?>> Exceptions = List.of(ServiceUnavailable.class);

    @Override
    public boolean test(Throwable t) {
        return Exceptions.contains(t.getClass());
    }
}

修复测试

您有 2 个选项,具体取决于您是否希望谓词传递给子类:

  • 将 ServiceUnavailable 的实际实例传递给 test()(使用 new 而不是模拟)
  • 在测试中使用 instanceof 检查(使用 stream 和 anyMatch,但在例外列表中)

所有这些都假定这是伪代码并且您的例外列表更长。 如果你想用一个 class 来测试你的 throwable,一个 lambda 就足够了:

Predicate<Throwable> pThrowable1 = t -> t instanceof ServiceUnavailable; // if you care about subclasses
Predicate<Throwable> pThrowable2 = t -> ServiceUnavailable.class.equals(t.getClass()); // if you want strict equality

更新:模拟内联

如果你使用mockito-inline ,它会改变模拟的构造方式:

这个替代模拟制造商使用 Java 工具 API 和子类的组合,而不是创建一个新的 class 来表示模拟。

InlineByteBuddyMockMaker javadoc说:

这个 mock maker 将尽最大努力在创建 mock 时避免创建子类。 否则它将使用org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker来创建模拟 class。这意味着以下条件为真

class Foo { } assert mock(Foo.class).getClass() == Foo.class;

除非满足以下任何条件,在这种情况下,mock maker 会回退到创建子类。

  • 模拟的类型是一个抽象的 class。
  • 模拟设置为需要额外的接口。
  • 模拟被显式设置为支持序列化

因此,如果您使用 mockito-inline 测试通过,因为没有创建子类:

var serviceUnavailableMock = mock(ServiceUnavailable.class);
System.out.println(serviceUnavailableMock.getClass());
System.out.println(serviceUnavailableMock.getClass() == ServiceUnavailable.class);
System.out.println(serviceUnavailableMock instanceof ServiceUnavailable);

// class org.example.ServiceUnavailable
// true
// true

所以问题是我在 pom.xml 中没有 mockito-inline jar。 不知道为什么,但这解决了问题

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM