java - 如何使用 mockito 模拟 grpc ServiceBlockingStub 抛出 StatusRuntimeException(Status.UNAVAILABLE)?

标签 java mockito grpc

我想模拟我的 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);
    }

不幸的是,我按预期得到了以下异常:
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)
.
.
.

因为我尝试模拟 grpc 生成的最终类:
  public static final class BlahServiceBlockingStub extends io.grpc.stub.AbstractStub<BlahServiceBlockingStub> {
    private BlahServiceBlockingStub(io.grpc.Channel channel) {
      super(channel);
    }

最佳答案

不要模拟客户端 stub 或任何其他最终类/方法。 gRPC 团队可能会不遗余力地破坏您对此类模拟的使用,因为它们非常脆弱,可能会产生“不可能”的结果。

模拟服务,而不是客户端 stub 。当与过程中的传输相结合时,它可以进行快速、可靠的测试。这与 grpc-java hello world example 中演示的方法相同.

@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);
}

在进行多个测试时,您可以将服务器、 channel 和 stub 创建提升到字段或 @Before 中。 ,在个人测试之外。这样做时可以方便地使用 MutableHandlerRegistry作为 fallbackHandlerRegistry()在服务器上。这允许您在服务器启动后注册服务。见 route guide example有关该方法的更完整示例。

关于java - 如何使用 mockito 模拟 grpc ServiceBlockingStub 抛出 StatusRuntimeException(Status.UNAVAILABLE)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59536673/

相关文章:

java - 为spring data mongo指定多个基础包

java - 如何验证具有不同参数的多个方法调用

java - InjectedMock 中的 NullPointerException

php - gRPC 在终端中工作但不在 laravel 项目中

python - 使用 python 将纯 JSON 发送到 gRPC 服务器

Java,Lucene : Get document by saved Id and then update one of it's field

java - 想知道是否有办法让 JUnit 类运行其他 JUnit 测试类

java - EL 变量内的恒定分辨率

java - 使用 Mockito 模拟 Joda DateTime 方法

python - BigTable 和 gRPC - 内存泄漏,如何解决?