我想模拟我的 grpc 客户端,以确保它通过抛出一个new StatusRuntimeException(Status.UNAVAILABLE)(这是java.net.ConnectException: Connection refused向 grpc 客户端抛出的异常)来应对失败。但是,生成的类是最终的,因此模拟将不起作用。
如何让 BlahServiceBlockingStub 抛出new StatusRuntimeException(Status.UNAVAILABLE)而不必重构我的代码来创建围绕 BlahServiceBlockingStub 的包装类?
这是我尝试过的(其中 BlahServiceBlockingStub 是由 grpc 生成的):
@Test
public void test() {
BlahServiceBlockingStub blahServiceBlockingStub = mock(BlahServiceBlockingStub.class);
when(blahServiceBlockingStub.blah(any())).thenThrow(new StatusRuntimeException(Status.UNAVAILABLE));
blahServiceBlockingStub.blah(null);
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,我按预期得到了以下异常:
org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class BlahServiceGrpc$BlahServiceBlockingStub
Mockito cannot mock/spy following:
- final classes
- anonymous classes
- primitive types
at MyTestClass.test(MyTestClass.java:655)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
.
.
.
Run Code Online (Sandbox Code Playgroud)
因为我尝试模拟 grpc 生成的最终类:
public static final class BlahServiceBlockingStub extends io.grpc.stub.AbstractStub<BlahServiceBlockingStub> {
private BlahServiceBlockingStub(io.grpc.Channel channel) {
super(channel);
}
Run Code Online (Sandbox Code Playgroud)
不要模拟客户端存根或任何其他最终类/方法。gRPC 团队可能会不遗余力地破坏您对此类模拟的使用,因为它们非常脆弱,可能会产生“不可能”的结果。
模拟服务,而不是客户端存根。当与过程中的传输相结合时,它可以进行快速、可靠的测试。这与grpc-java hello world 示例中演示的方法相同。
@Rule
public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule();
@Test
public void test() {
// This can be a mock, but is easier here as a fake implementation
BlahServiceImplBase serviceImpl = new BlahServiceImplBase() {
@Override public void blah(Request req, StreamObserver<Response> resp) {
resp.onError(new StatusRuntimeException(Status.UNAVAILABLE));
}
};
// Note that the channel and server can be created in any order
grpcCleanup.register(InProcessServerBuilder.forName("mytest")
.directExecutor().addService(serviceImpl).build().start());
ManagedChannel chan = grpcCleanup.register(
InProcessChannelBuilder.forName("mytest").directExecutor().build();
BlahServiceBlockingStub blahServiceBlockingStub
= BlahServiceGrpc.newBlockingStub();
blahServiceBlockingStub.blah(null);
}
Run Code Online (Sandbox Code Playgroud)
在进行多个测试时,您可以将服务器、通道和存根创建提升到@Before各个测试中的字段或。这样做的时候,它可以方便地使用MutableHandlerRegistry作为一个fallbackHandlerRegistry()在服务器上。这允许您在服务器启动后注册服务。有关该方法的更完整示例,请参阅路线指南示例。
您有几个选择:
请注意为什么在这种情况下模拟 Final 可能是一个坏主意: 根据情况,模拟 Final 类或方法可能是一个坏主意。细节决定成败。在您的情况下,您正在创建生成的代码的模拟,因此您假设生成的代码将来的行为方式。gRPC 和 Protobuf 仍在快速发展,因此做出这些假设可能存在风险,因为它们可能会发生变化,而您不会注意到,因为您没有根据生成的代码检查模拟。因此,除非确实需要,否则模拟生成的代码并不是一个好主意。
| 归档时间: |
|
| 查看次数: |
5316 次 |
| 最近记录: |