Testing gRPC
The tests in the Hello World example illustrates use of the JUnit framework. The test coverage is not complete. It only shows how to get started with testing gRPC services. You could add to it as an exercise to increase your own knowledge.
Let’s look at the test class definition in the GreeterTest.java
source file:
sourcepackage com.example.helloworld;
import akka.actor.testkit.typed.javadsl.ActorTestKit;
import akka.actor.testkit.typed.javadsl.TestKitJunitResource;
import akka.actor.typed.ActorSystem;
import akka.actor.typed.javadsl.Behaviors;
import akka.grpc.GrpcClientSettings;
import akka.http.javadsl.ServerBinding;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertEquals;
public class GreeterTest {
// important to enable HTTP/2 in server ActorSystem's config
private static final Config config = ConfigFactory
.parseString("akka.http.server.preview.enable-http2 = on")
.withFallback(ConfigFactory.defaultApplication());
@ClassRule
public static final TestKitJunitResource testKit = new TestKitJunitResource(config);
private static ActorSystem<?> serverSystem = testKit.system();
private static ActorSystem<?> clientSystem;
private static GreeterServiceClient client;
@BeforeClass
public static void setup() throws Exception {
CompletionStage<ServerBinding> bound = new GreeterServer(serverSystem).run();
// make sure server is bound before using client
bound.toCompletableFuture().get(5, TimeUnit.SECONDS);
clientSystem = ActorSystem.create(Behaviors.empty(), "GreeterClient");
// the host and TLS certificate config are picked up from the config file
client = GreeterServiceClient.create(
GrpcClientSettings.fromConfig("helloworld.GreeterService", clientSystem),
clientSystem
);
}
@AfterClass
public static void teardown() {
ActorTestKit.shutdown(clientSystem);
client = null;
}
@Test
public void greeterServiceRepliesToSingleRequest() throws Exception {
HelloReply reply = client.sayHello(HelloRequest.newBuilder().setName("Alice").build())
.toCompletableFuture()
.get(5, TimeUnit.SECONDS);
HelloReply expected = HelloReply.newBuilder().setMessage("Hello, Alice").build();
assertEquals(expected, reply);
}
}
Note how we create two ActorSystem
s, one for the server and another for the client. The test is then using the client to verify that it retrieves the expected responses from the server.
Unit testing
The above test example is a full integration test using real client and server, including communication via HTTP/2. For some testing of the service implementation it might be more appropriate to write unit tests without interaction via the gRPC client. Since the service interface and implementation doesn’t require any gRPC infrastructure it can be tested without binding it to a HTTP server.
sourcepackage com.example.helloworld;
import akka.actor.testkit.typed.javadsl.ActorTestKit;
import akka.actor.testkit.typed.javadsl.TestKitJunitResource;
import akka.actor.typed.ActorSystem;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertEquals;
public class GreeterServiceImplTest {
@ClassRule
public static final TestKitJunitResource testKit = new TestKitJunitResource();
private static ActorSystem<?> system = testKit.system();
private static GreeterService service;
@BeforeClass
public static void setup() {
service = new GreeterServiceImpl(system);
}
@Test
public void greeterServiceRepliesToSingleRequest() throws Exception {
HelloReply reply = service.sayHello(HelloRequest.newBuilder().setName("Bob").build())
.toCompletableFuture()
.get(5, TimeUnit.SECONDS);
HelloReply expected = HelloReply.newBuilder().setMessage("Hello, Bob").build();
assertEquals(expected, reply);
}
}
Add streaming tests
As an exercise to increase your understanding you could add tests for the streaming call, both as integration test and unit test style.
The Akka documentation of Testing streams might be useful.