0

I have an akka based application, and it has Application.java file which has structure like what we have defined here.

Now I want to write integration tests for akka http endpoints in this application, as discussed here.

It says that I need to launch application in @BeforeClass method.

So how do I start application. I guess merely calling main function wont work as it would block the program and tests would never hit.

1 Answer 1

0

I understand that you want to start a real http server for your integration test. You could extract the logic inside main method to another one and return the ActorSystem created.

    public static ActorSystem<NotUsed> startActorSystem() {
        //#server-bootstrapping
        Behavior<NotUsed> rootBehavior = Behaviors.setup(context -> {
            ActorRef<UserRegistry.Command> userRegistryActor =
                    context.spawn(UserRegistry.create(), "UserRegistry");

            UserRoutes userRoutes = new UserRoutes(context.getSystem(), userRegistryActor);
            startHttpServer(userRoutes.userRoutes(), context.getSystem());

            return Behaviors.empty();
        });

        // boot up server using the route as defined below
        return ActorSystem.create(rootBehavior, "HelloAkkaHttpServer");
        //#server-bootstrapping
    }

Then, you can start the real server invoking that method

var actorSystem = actorSystem = QuickstartApp.startActorSystem();

Now you can send real http requests to the server instead of testing the routes isolated.

Your new test should look like the following

import akka.NotUsed;
import akka.actor.typed.ActorSystem;
import akka.http.javadsl.Http;
import akka.http.javadsl.marshallers.jackson.Jackson;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.model.MediaTypes;
import org.junit.*;
import org.junit.runners.MethodSorters;

import java.util.concurrent.ExecutionException;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class UserRoutesIntegrationTest {

    private static ActorSystem<NotUsed> actorSystem;

    @BeforeClass
    public static void beforeClass() {
        // ---------------------------
        // START THE REAL SERVER HERE
        // ---------------------------
        actorSystem = QuickstartApp.startActorSystem();
    }

    @AfterClass
    public static void afterClass() {
        // ------------------------------
        // SHUT DOWN THE REAL SERVER HERE
        // ------------------------------
        actorSystem.terminate();
    }

    @Test
    public void test1NoUsers() throws ExecutionException, InterruptedException {
        // ------------------------------------------
        // SEND REAL HTTP REQUEST TO REAL HTTP SERVER
        // ------------------------------------------
        var responseCompletionStage = Http
            .get(actorSystem)
            .singleRequest(HttpRequest.GET("http://localhost:8080/users"));
        // ---------------------------
        // UNMARSHAL THE HTTP RESPONSE
        // ---------------------------
        var usersCompletionStage = responseCompletionStage
                .thenCompose(response -> Jackson.unmarshaller(UserRegistry.Users.class).unmarshal(response.entity(), actorSystem));
        var users = usersCompletionStage.toCompletableFuture().get();
        // ----------
        // ASSERTIONS
        // ----------
        assertTrue(users.users().isEmpty());
    }

    @Test
    public void test2HandlePOST() throws ExecutionException, InterruptedException {
        var responseCompletionStage = Http
            .get(actorSystem)
            .singleRequest(
                HttpRequest
                    .POST("http://localhost:8080/users")
                    .withEntity(
                        MediaTypes.APPLICATION_JSON.toContentType(),
                        """
                                {
                                    "name": "Kapi",
                                    "age": 42,
                                    "countryOfResidence": "jp"
                                }
                            """
                    )
                );

        var actionPerformedCompletionStage = responseCompletionStage
                .thenCompose(response -> Jackson
                        .unmarshaller(UserRegistry.ActionPerformed.class)
                        .unmarshal(response.entity(), actorSystem));
        var actionPerformed = actionPerformedCompletionStage.toCompletableFuture().get();
        assertEquals("User Kapi created.", actionPerformed.description());
    }

    @Test
    public void test3Remove() throws ExecutionException, InterruptedException {
        var responseCompletionStage = Http
                .get(actorSystem)
                .singleRequest(HttpRequest.DELETE("http://localhost:8080/users/Kapi"));
        var actionPerformedCompletionStage = responseCompletionStage
                .thenCompose(response -> Jackson
                        .unmarshaller(UserRegistry.ActionPerformed.class)
                        .unmarshal(response.entity(), actorSystem));
        var actionPerformed = actionPerformedCompletionStage.toCompletableFuture().get();
        assertEquals("User Kapi deleted.", actionPerformed.description());
    }
}

This is a dummy example of an integration test because you only need to start the http server. In case you need a database, a message queue or even another real server running in a docker container you could use something like Java Testcontainers.

Have also in mind that you are hardcoding many things in your main class, such as the port or interface. It could be a good idea to do some refactor and receive some values or a Config object by param to make your tests more flexibles

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.