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?
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".