用于单元测试的模拟 gRPC 服务

每日分享最新,最流行的软件开发知识与最新行业趋势,希望大家能够一键三连,多多支持,跪求关注,点赞,留言。

#双十一好物狂欢节#

从一开始,测试就会开始。因此,与这些组件的交互应该在测试环境中处理。一种方法是使用这些组件的安装(或模拟器)并让代码与实际实例交互,就像通过使用测试容器或创建仅用于测试目的的基础设施来实现的方式一样。
另一种方法是启动组件的模拟服务并让测试与之交互。Hoverfly就是一个很好的例子。一个模拟的 HTTP 服务在测试期间运行,测试用例与之交互。

根据我们的测试过程所需的质量,两者都可以在各种情况下使用。我们将重点关注应用于gRPC的第二种方法。

众所周知,大多数Google Cloud 组件都带有 gRPC API。在我们的场景中,我们有一个向 Pub/Sub 发布消息的应用程序。

<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>libraries-bom</artifactId>
<version>24.1.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-pubsub</artifactId>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-testing</artifactId>
<version>1.43.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.api.grpc</groupId>
<artifactId>grpc-google-cloud-pubsub-v1</artifactId>
<version>1.97.1</version>
<scope>test</scope>
</dependency>
</dependencies>

让我们从我们的发布者类开始。
package
com.egkatzioura.notification.publisher;


import
java.util.concurrent.CompletableFuture;

import
java.util.concurrent.Executor;


import
com.google.api.core.ApiFuture;

import
com.google.api.core.ApiFutureCallback;

import
com.google.api.core.ApiFutures;

import
com.google.cloud.pubsub.v1.Publisher;

import
com.google.protobuf.ByteString;

import
com.google.pubsub.v1.PubsubMessage;


public class UpdatePublisher {

private final Publisher publisher;
private final Executor executor;

public UpdatePublisher(Publisher publisher, Executor executor) {
this.publisher = publisher;
this.executor = executor;
}

public CompletableFuture<String> update(String notification) {
PubsubMessage pubsubMessage = PubsubMessage.newBuilder()
.setData(ByteString.copyFromUtf8(notification))
.build();
ApiFuture<String> apiFuture = publisher.publish(pubsubMessage);

return toCompletableFuture(apiFuture);
}

private CompletableFuture<String> toCompletableFuture(ApiFuture<String> apiFuture) {
final CompletableFuture<String> responseFuture = new CompletableFuture<>();

ApiFutures.addCallback(apiFuture, new ApiFutureCallback<>() {
@Override
public void onFailure(Throwable t) {

responseFuture.completeExceptionally(t);

}

@Override
public void onSuccess(String result) {
responseFuture.complete(result);
}

}, executor);
return responseFuture;
}

}
发布者将发送消息并返回所发送消息 ID 的 CompletableFuture。
所以让我们测试这个类。我们的目标是发送消息并取回消息 ID。模拟和模拟的服务是 Pub/Sub。

为此,我们添加了对 Maven 的 gRPC API 依赖。

<dependency>
<groupId>com.google.api.grpc</groupId>
<artifactId>grpc-google-cloud-pubsub-v1</artifactId>
<version>1.97.1</version>
<scope>test</scope>
</dependency>

我们将模拟用于发布操作的 API。要实现的类是
PublisherGrpc.PublisherImplBase。


package
com.egkatzioura.notification.publisher;


import java.util.UUID;

import
com.google.pubsub.v1.PublishRequest;

import
com.google.pubsub.v1.PublishResponse;

import
com.google.pubsub.v1.PublisherGrpc;


import
io.grpc.stub.StreamObserver;


public class MockPublisherGrpc extends
PublisherGrpc.PublisherImplBase {


private final String prefix;

public MockPublisherGrpc(String prefix) {
this.prefix = prefix;
}

@Override
public void publish(PublishRequest request, StreamObserver<PublishResponse> responseObserver) {
responseObserver.onNext(
PublishResponse.newBuilder().addMessageIds(prefix+”:”+UUID.randomUUID().toString()).build());


responseObserver.onCompleted();

}

}
如您所见,消息 ID 将具有我们定义的前缀。

这将是服务器端的 PublisherGrpc 实现。让我们继续进行单元测试。UpdatePublisher 类可以注入一个 Publisher。此发布者将被配置为使用之前创建的
PublisherGrpc.PublisherImplBase。

@Rule
public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule();

private static final String MESSAGE_ID_PREFIX = “message”;

@Before
public void setUp() throws Exception {
String serverName = InProcessServerBuilder.generateName();

Server server = InProcessServerBuilder
.forName(serverName).directExecutor().addService(new MockPublisherGrpc(MESSAGE_ID_PREFIX)).build().start();

grpcCleanup.register(server);

上面我们创建了一个为进程内请求提供服务的 GRPC 服务器。然后我们注册了之前创建的模拟服务。

向前!我们使用该服务创建 Publisher 并创建要测试的类的实例。

@Before
public void setUp() throws Exception {
String serverName = InProcessServerBuilder.generateName();

Server server = InProcessServerBuilder
.forName(serverName).directExecutor().addService(new MockPublisherGrpc(MESSAGE_ID_PREFIX)).build().start();

grpcCleanup.register(server);

ExecutorProvider executorProvider = testExecutorProvider();
ManagedChannel managedChannel = InProcessChannelBuilder.forName(serverName).directExecutor().build();

TransportChannel transportChannel = GrpcTransportChannel.create(managedChannel);
TransportChannelProvider transportChannelProvider = FixedTransportChannelProvider.create(transportChannel);

String topicName = “projects/test-project/topic/my-topic”;
Publisher publisher = Publisher.newBuilder(topicName)
.setExecutorProvider(executorProvider)
.setChannelProvider(transportChannelProvider)
.build();

updatePublisher = new UpdatePublisher(publisher, Executors.newSingleThreadExecutor());

我们将 Channel 传递给指向 InProcessServer 的发布者。请求将被路由到我们注册的服务。最后,我们可以添加我们的测试。

@Test
public void testPublishOrder() throws ExecutionException, InterruptedException {
String messageId = updatePublisher.update(“Some notification”).get();
assertThat(messageId, containsString(MESSAGE_ID_PREFIX));
}

我们做到了!我们创建了进程内 gRPC 服务器,以便对 gRPC 驱动的服务进行测试。

你可以在GitHub 上找到代码!

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2022年9月19日
下一篇 2022年9月19日

相关推荐