Mockito的具体化mock方法将mock类型作为超类而不是泛型类型

jvlzgdj9  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(154)

我想提供一个更简单的接口(实用方法)来模拟一个类的构造,我们经常需要在许多测试中模拟它,因为它是由第三方库构造的。这个类是泛型类型的,并且有一个方法返回它的泛型(ClassIWantMockedConstructor<T> { whatever(): T })。实用方法是这样的:

public interface Execution<T extends ParentClass> {
    void execute(T mock) throws Exception;
}
    
public static <T extends ParentClass> void withMockedConstruction(Execution<T> execution) {
    T mock = mock();
    try (@SuppressWarnings("unused") MockedConstruction<?> construction = mockConstruction(
            ClassIWantMockedConstructor.class,
            (mocked, ctx) -> when(mocked.whatever()).thenReturn(mock)
    )) {
        execution.execute(mock);
    } catch (Throwable t) {
        throw new RuntimeException("Unexpected error during tests, please check the tests", t);
    }
}

字符串
但是,如果我使用withMockedConstruction传递一个lambda类型,而该lambda类型是ParentClass的子类,那么T仍然是ParentClass类型。这将导致后面的ClassCastException。示例:

// When called like this
withMockedConstruction((ChildClass mockService) -> { ... });

// Then debugging
public static <T extends ParentClass> void withMockedConstruction(Execution<T> execution) {
    T mock = mock(); // mock = Mock for ParentClass, T reified as ParentClass
    ...
        execution.execute(mock); // throws ClassCastException
}


我能克服这个问题的唯一方法是手动为mock指定一个类,从而将签名更改为需要类,如下所示:

// Change signature to this:
public static <T extends ParentClass> void withMockedConstruction(Class<T> clazz, Execution<T> execution) {
    T mock = mock(clazz); // mock = Mock for ChildClass normally
    ...
}

// Calling like this, works as intended
withMockedConstruction(ChildClass.class, mockService -> { ... });


有没有什么方法可以通过只使用refied来实现这个结果?我可以以某种方式强制它检查lambda函数的refied类型吗?在这种情况下使用类是最好的解决方案吗?

kzipqqlq

kzipqqlq1#

用于具体化泛型的“技巧”不能传递地工作:您不能自己使用泛型并期望技巧工作。

public static <T extends ParentClass> void withMockedConstruction(
      Execution<T> execution) {
    T mock = mock();

字符串
在运行时,T被擦除为ParentClass,因此mock()将具体化ParentClass,而不是T(我想这意味着这是@SafeVarargs实际上是错误的特定情况)。
你可以 * 也许 * 确定lambda的参数类型,可能是一个自定义函数接口,默认方法采用像这样的技巧,但在这一点上,与简单地传递Class相比,你并没有节省多少东西,因为你必须始终使用括号指定lambda参数类型。

相关问题