akka-http icon indicating copy to clipboard operation
akka-http copied to clipboard

Add docs for using testkits with Junit 5

Open johanandren opened this issue 6 years ago • 5 comments

Sister-ticket of akka/akka#27155

We since previously have a request to migrate to JUnit 5 but since the demand has been so low I'm not sure if we want to do that, however, I think we should show in docs how to use the testkit with JUnit 5

Alpakka Kafka has done this in the docs here https://doc.akka.io/docs/alpakka-kafka/current/testing.html#testing-from-java-code

johanandren avatar Jun 17 '19 10:06 johanandren

I'm having a hard time getting akka-http testing setup in a project that already uses JUnit5 (and which wont will switch back to JUnit4 just cause of Akka-HTTP). Any pointers on something existing I can take a look at to get this running?

domdorn avatar Jul 16 '20 09:07 domdorn

See also #1476

jrudolph avatar Jul 16 '20 10:07 jrudolph

In a gradle build setup adding the vintage engine helped with the tests failing.

dependencies {
   testImplementation("org.junit.vintage:junit-vintage-engine:5.8.2")
}

danhallin avatar Jun 18 '22 17:06 danhallin

I still couldn't get testRoute() working, even with vintage-engine lib added. I ended up with custom base test class implementation. I'm sharing it here in case it helps someone:

import akka.http.javadsl.testkit.ActorSystemResource;
import akka.http.javadsl.testkit.JUnitRouteTestBase;
import com.typesafe.config.ConfigFactory;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;

public class RouteTestBase extends JUnitRouteTestBase {
    private static final ActorSystemResource systemResource = new ActorSystemResource(
            "TestSystem",
            ConfigFactory.empty());


    @BeforeAll
    public static void before() {
        systemResource.before();
    }

    @AfterAll
    public static void after() {
        systemResource.after();
    }

    @Override
    public ActorSystemResource systemResource() {
        return systemResource;
    }
}

With this approach you still need org.junit.vintage:junit-vintage-engine as some akka-http-teskit internals depend on Junit4 classes.

0bx avatar Mar 15 '23 19:03 0bx

The above was helpful, I'll add some details on what it took to get the akka-http-quickstart-java tests to run.

The dependencies + the surefire plugin:

<dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.9.2</version>
        <scope>test</scope>
</dependency>
 <dependency>
        <groupId>org.junit.vintage</groupId>
        <artifactId>junit-vintage-engine</artifactId>
        <version>5.9.2</version>
        <scope>test</scope>
 </dependency>
<plugin>                
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <!-- JUnit 5 requires Surefire version 2.22.0 or higher -->
    <version>2.22.0</version>
</plugin>

And the test:

package com.example;

import akka.actor.testkit.typed.javadsl.TestKitJunitResource;
import akka.actor.typed.ActorRef;
import akka.actor.typed.ActorSystem;
import akka.actor.typed.javadsl.Adapter;
import akka.http.javadsl.model.*;
import akka.http.javadsl.testkit.ActorSystemResource;
import akka.http.javadsl.testkit.JUnitRouteTestBase;
import akka.http.javadsl.testkit.TestRoute;
import com.typesafe.config.ConfigFactory;
import org.junit.ClassRule;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.model.StatusCodes;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class UserRoutesTest extends JUnitRouteTestBase {
    private static final ActorSystemResource systemResource = new ActorSystemResource(
            "TestSystem",
            ConfigFactory.empty());

    // shared registry for all tests
    private static ActorRef<UserRegistry.Command> userRegistry;
    private TestRoute appRoute;

    @ClassRule
    public static TestKitJunitResource testkit = new TestKitJunitResource();

    @BeforeAll
    public void before() {
        systemResource.before();
        ActorSystem<Void> typedActorSystem = Adapter.toTyped(systemResource.system());
        userRegistry = testkit.spawn(UserRegistry.create());
        UserRoutes userRoutes = new UserRoutes(typedActorSystem, userRegistry);
        appRoute = testRoute(userRoutes.userRoutes());
    }

    @AfterAll
    public static void after() {
        systemResource.after();
    }

    @Override
    public ActorSystemResource systemResource() {
        return systemResource;
    }

    @Test
    public void test1NoUsers() {
        appRoute.run(HttpRequest.GET("/users"))
                .assertStatusCode(StatusCodes.OK)
                .assertMediaType("application/json")
                .assertEntity("{\"users\":[]}");
    }

    @Test
    public void test2HandlePOST() {
        appRoute.run(HttpRequest.POST("/users")
                .withEntity(MediaTypes.APPLICATION_JSON.toContentType(),
                        "{\"name\": \"Kapi\", \"age\": 42, \"countryOfResidence\": \"jp\"}"))
                .assertStatusCode(StatusCodes.CREATED)
                .assertMediaType("application/json")
                .assertEntity("{\"description\":\"User Kapi created.\"}");
    }

    @Test
    public void test3Remove() {
        appRoute.run(HttpRequest.DELETE("/users/Kapi"))
                .assertStatusCode(StatusCodes.OK)
                .assertMediaType("application/json")
                .assertEntity("{\"description\":\"User Kapi deleted.\"}");

    }
}

sean-walsh avatar Apr 17 '23 14:04 sean-walsh