我想提供一个更简单的接口(实用方法)来模拟一个类的构造,我们经常需要在许多测试中模拟它,因为它是由第三方库构造的。这个类是泛型类型的,并且有一个方法返回它的泛型(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类型吗?在这种情况下使用类是最好的解决方案吗?
1条答案
按热度按时间kzipqqlq1#
用于具体化泛型的“技巧”不能传递地工作:您不能自己使用泛型并期望技巧工作。
字符串
在运行时,
T
被擦除为ParentClass
,因此mock()
将具体化ParentClass
,而不是T
(我想这意味着这是@SafeVarargs
实际上是错误的特定情况)。你可以 * 也许 * 确定lambda的参数类型,可能是一个自定义函数接口,默认方法采用像这样的技巧,但在这一点上,与简单地传递
Class
相比,你并没有节省多少东西,因为你必须始终使用括号指定lambda参数类型。