Akka testkit with typed not compiling

332 Views Asked by At

I'm attempting to setup a simple Akka test using Testkit using following code :

import akka.actor.typed.ActorRef;
import akka.actor.typed.Behavior;
import akka.actor.typed.Scheduler;
import akka.actor.typed.javadsl.AskPattern;
import akka.actor.typed.javadsl.Behaviors;
// #test-header

//import akka.actor.testkit.typed.javadsl.*;

import akka.actor.testkit.typed.javadsl.TestInbox;
// #test-header
import akka.actor.testkit.typed.javadsl.TestProbe;
import org.junit.AfterClass;
import org.junit.Test;
import org.scalatestplus.junit.JUnitSuite;

import java.time.Duration;
import java.util.concurrent.CompletionStage;
import java.util.stream.IntStream;

import java.util.Objects;

import static org.junit.Assert.assertEquals;

// #test-header
public class AsyncTestingExampleTest
        // #test-header
        extends JUnitSuite
// #test-header
{
    static final ActorTestKit testKit = ActorTestKit.create();
    // #test-header

    // #under-test
    public static class Echo {
        public static class Ping {
            public final String message;
            public final ActorRef<Pong> replyTo;

            public Ping(String message, ActorRef<Pong> replyTo) {
                this.message = message;
                this.replyTo = replyTo;
            }
        }

        public static class Pong {
            public final String message;

            public Pong(String message) {
                this.message = message;
            }

            @Override
            public boolean equals(Object o) {
                if (this == o) return true;
                if (!(o instanceof Pong)) return false;
                Pong pong = (Pong) o;
                return message.equals(pong.message);
            }

            @Override
            public int hashCode() {
                return Objects.hash(message);
            }
        }

        public static Behavior<Ping> create() {
            return Behaviors.receive(Ping.class)
                    .onMessage(
                            Ping.class,
                            ping -> {
                                ping.replyTo.tell(new Pong(ping.message));
                                return Behaviors.same();
                            })
                    .build();
        }
    }
    // #under-test

    // #under-test-2

    static class Message {
        int i;
        ActorRef<Integer> replyTo;

        Message(int i, ActorRef<Integer> replyTo) {
            this.i = i;
            this.replyTo = replyTo;
        }
    }

    public static class Producer {

        private Scheduler scheduler;
        private ActorRef<Message> publisher;

        Producer(Scheduler scheduler, ActorRef<Message> publisher) {
            this.scheduler = scheduler;
            this.publisher = publisher;
        }

        public void produce(int messages) {
            IntStream.range(0, messages).forEach(this::publish);
        }

        private CompletionStage<Integer> publish(int i) {
            return AskPattern.ask(
                    publisher,
                    (ActorRef<Integer> ref) -> new Message(i, ref),
                    Duration.ofSeconds(3),
                    scheduler);
        }
    }
    // #under-test-2

    // #test-shutdown
    @AfterClass
    public static void cleanup() {
        testKit.shutdownTestKit();
    }
    // #test-shutdown

    @Test
    public void testVerifyingAResponse() {
        // #test-spawn
        ActorRef<Echo.Ping> pinger = testKit.spawn(Echo.create(), "ping");
        TestProbe<Echo.Pong> probe = testKit.createTestProbe();
        pinger.tell(new Echo.Ping("hello", probe.ref()));
        probe.expectMessage(new Echo.Pong("hello"));
        // #test-spawn
    }

    @Test
    public void testVerifyingAResponseAnonymous() {
        // #test-spawn-anonymous
        ActorRef<Echo.Ping> pinger = testKit.spawn(Echo.create());
        // #test-spawn-anonymous
        TestProbe<Echo.Pong> probe = testKit.createTestProbe();
        pinger.tell(new Echo.Ping("hello", probe.ref()));
        probe.expectMessage(new Echo.Pong("hello"));
    }

    @Test
    public void testStoppingActors() {
        TestProbe<Echo.Pong> probe = testKit.createTestProbe();
        // #test-stop-actors
        ActorRef<Echo.Ping> pinger1 = testKit.spawn(Echo.create(), "pinger");
        pinger1.tell(new Echo.Ping("hello", probe.ref()));
        probe.expectMessage(new Echo.Pong("hello"));
        testKit.stop(pinger1);

        // Immediately creating an actor with the same name
        ActorRef<Echo.Ping> pinger2 = testKit.spawn(Echo.create(), "pinger");
        pinger2.tell(new Echo.Ping("hello", probe.ref()));
        probe.expectMessage(new Echo.Pong("hello"));
        testKit.stop(pinger2, Duration.ofSeconds(10));
        // #test-stop-actors
    }

    @Test
    public void testObserveMockedBehavior() {
        // #test-observe-mocked-behavior
        // simulate the happy path
        Behavior<Message> mockedBehavior =
                Behaviors.receiveMessage(
                        message -> {
                            message.replyTo.tell(message.i);
                            return Behaviors.same();
                        });
        TestProbe<Message> probe = testKit.createTestProbe();
        ActorRef<Message> mockedPublisher =
                testKit.spawn(Behaviors.monitor(Message.class, probe.ref(), mockedBehavior));

        // test our component
        Producer producer = new Producer(testKit.scheduler(), mockedPublisher);
        int messages = 3;
        producer.produce(messages);

        // verify expected behavior
        IntStream.range(0, messages)
                .forEach(
                        i -> {
                            Message msg = probe.expectMessageClass(Message.class);
                            assertEquals(i, msg.i);
                        });
        // #test-observe-mocked-behavior
    }

    @Test
    public void systemNameShouldComeFromTestClass() {
        assertEquals(testKit.system().name(), "AsyncTestingExampleTest");
    }
    // #test-header
}
// #test-header

This code based on : https://doc.akka.io/docs/akka/current/typed/testing-async.html#configuration

The dependency pom.xml for related code is :

which is using Akka Testkit dependency from https://doc.akka.io/docs/akka/current/typed/testing-async.html#configuration

<properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <scala.binary.version>2.13</scala.binary.version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.typesafe.akka</groupId>
            <artifactId>akka-bom_${scala.binary.version}</artifactId>
            <version>2.6.14</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>com.typesafe.akka</groupId>
        <artifactId>akka-stream_2.13</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.3.3</version>
    </dependency>
    <dependency>
        <groupId>com.typesafe.akka</groupId>
        <artifactId>akka-actor-typed_${scala.binary.version}</artifactId>
    </dependency>
    <dependency>
        <groupId>com.typesafe.akka</groupId>
        <artifactId>akka-actor-testkit-typed_${scala.binary.version}</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

The issue is the compiler is not finding some of the imported classes such as :

import akka.actor.testkit.typed.javadsl.TestInbox;
// #test-header
import akka.actor.testkit.typed.javadsl.TestProbe;
import org.junit.AfterClass;
import org.junit.Test;
import org.scalatestplus.junit.JUnitSuite

And fails with error "Cannot resolve symbol" for each of the above classes.

I've tried clearing my Maven dependencies but it appears I've not setup the dependencies correctly.

Is there another dependency that is required in order to use Akka Typed Testkit for Java?

1

There are 1 best solutions below

0
On

The answer is so obvious now. I overlooked the fact that I was executing the test code from a non-test directory and as the scope of the test dependencies is test these libraries were not available. In addition, the answer for me here was to just "sleep on it".