Akka - Test that function from test executed - scala

I have the following trait
trait MyTrait{
def printHelloWorld(){
println("hello world")
}
}
case object SayHello
class MyActor extends Actor with MyTrait{
def recieve = {
case SayHello => printHelloWorld
}
}
Now I'm trying to create Unit Test which test then Say Hello Object invokes printing hello message
"My Actor" should{
"println hello msg if SayHello sent" in{
val myTraitMock = mock[MyTrait]
val myActor = system.actorOf(Props(new MyActor))
myActor ! SayHello
Thread.sleep(500)
there was atLeastOne(myTraitMock).printHelloMessage
}
}
However this unit test is always green. Even if I replace this method with simple println method.
Is there any other method to test such case?

How about this:
trait MyActor extends Actor{self:MyTrait
def recieve = {
case SayHello => printHelloWorld
}
}
class MyMainActor extends MyActor with MyTrait
"My Actor" should{
"println hello msg if SayHello sent" in{
class MockActor extends MyActor with SomeMyTrait
val x = new MockActor
val myActor = system.actorOf(Props(x))
myActor ! SayHello
Thread.sleep(500)
there was atLeastOne(x).printHelloMessage
}
In general for actors, I am not a fan of above like testing.
Akka Test-kit is brilliant. I would highly recommend looking at it.
In which I would do :
trait MyTrait{
def printHelloWorld(){
println("hello world")
}
}
case object SayHello
case object Printed
class MyActor extends Actor with MyTrait{
def recieve = {
case SayHello => printHelloWorld
sender ! Printed
}
}
import akka.actor.ActorSystem
import akka.testkit.{ TestProbe, ImplicitSender, TestKit }
import org.scalatest.matchers.ShouldMatchers
import org.scalatest.{ BeforeAndAfterAll, FunSuite }
import scala.concurrent.duration._
class MyTest extends TestKit(ActorSystem("MyTest1"))
with FunSuite
with BeforeAndAfterAll
with ShouldMatchers
with ImplicitSender{
override def afterAll() { system.shutdown() }
test("MyTrait is called when triggered") {
val x = TestProbe()
val myActor = system.actorOf(Props(new MyActor))
myActor.send(x, SayHello)
x.expectMsg(Printed)
}

I know that it's an old question, but I had the same use case (fire and forget) and I came up with a simple solution using Probe:
case object SayHello
class MyActor(f: () => Unit) extends Actor{ // pass function as a parameter
def receive = {
case SayHello => f()
}
}
now if you want to create a test:
"test" {
val probe = TestProbe()
case object Executed
def mockF():Unit = {
println("test")
probe.ref ! Executed
}
val testActor = TestActorRef(Props(new MyActor(mockF)))
testActor ! SayHello
//probe.expectMsg blocks the thread, so it'll wait for Executed message.
probe.expectMsgPF(){case Executed => 1}
}
If you don't want to pass a function as a parameter then you can do the same thing with trait:
trait MyTraitImpl extends MyTrait{
def printHelloWorld(){
println("hello world")
}
}
trait MyTrait{
def printHelloWorld()
}
case object SayHello
class MyActor extends Actor{
myTrait:MyTrait =>
def receive = {
case SayHello => printHelloWorld
}
}
and test:
"test" {
val probe = TestProbe()
case object Executed
trait MyTraitMock extends MyTrait{
def printHelloWorld(){
println("hello world")
probe.ref ! Executed
}
}
val testActor = TestActorRef(Props(new MyActor() with MyTraitMock))
testActor ! SayHello
probe.expectMsgPF(){case Executed => 1}
}

You can test on what is printed to the EventFilter. So if your actor would print message like that:
case _ => log.info(printMessage)
you can then test
EventFilter.info(start="hello world", occurences=1).intercept {
MyActor ! SayHello
}

Related

Expect message on mocked actor when testing with TestKit

I am trying to test an actor, that depends on another actor. In the following test ActorA sends MessageA to ActorB and expects a MessageB in return.
Since this is a Unit test for ActorB, I am mocking ActorA. My problem now is, that i want to be sure that ActorA gets MessageA, but when i call the expectMsg (see the commented line) the whole autopilot does not seem to work anymore.
Am I doing something wrong here?
class MyTest(_system: ActorSystem) extends TestKit(_system)
with WordSpecLike
with BeforeAndAfterAll {
object Start
object MessageA
object MessageB
def this() = this(ActorSystem("TestSpec"))
override def afterAll() {
system.shutdown()
}
// will later be mocked
class ActorA extends Actor {
def receive = {
case MessageA => sender() ! MessageB
}
}
class ActorB(actorA: ActorRef) extends Actor {
def receive = {
case Start => actorA ! MessageA
case MessageB => println("Got MessageB")
}
}
"" should {
"work" in {
val actorA = TestProbe()
actorA.setAutoPilot(new AutoPilot {
override def run(sender: ActorRef, msg: Any): AutoPilot = {
msg match {
case MessageA => sender ! MessageB
}
TestActor.KeepRunning
}
})
// this will break the test
//actorA.expectMsg(MessageA)
val actor = system.actorOf(Props(new ActorB(actorA.ref)))
actor ! Start
}
}
}
You should expect MessageA after sending start to your ActorB.
val actor = system.actorOf(Props(new ActorB(actorA.ref)))
actor ! Start
// this will not break the test
actorA.expectMsg(MessageA)

Does ActorRef obtained via system.actorOf equal to self inside this actor?

I've designed an actor that should send its' actorRef to another actor on prestart:
class MyActor(notifier: ActorRef) extends Actor {
override def preStart(): Unit = {
notifier ! Register(self)
}
...
}
case class Register(actor: ActorRef)
Then I've written a specification for this Actor:
class MyActorSpec extends TestKit(ActorSystem("MyActorSpec"))
with ImplicitSender
with WordSpecLike
with Matchers
with BeforeAndAfterAll {
"MyActor" should {
val notifier = TestProbe()
"register itself in notifier" in {
val myActor = system.actorOf(Props(classOf[MyActor], notifier.ref))
notifier.expectMsg(Register(myActor))
}
}
}
When I run my test, it fails with the following message: assertion failed: expected Register(Actor[akka://MyActorSpec/user/$b#1849780829]), found Register(Actor[akka://MyActorSpec/user/$a#1143150267])
So, it seems that ActorRef obtained via self inside MyActor is not equal to ActorRef obtained via system.actorOf in my test. Any suggestions?
The following code is working just fine for me (the test passes):
class MyActor(notifier: ActorRef) extends Actor {
override def preStart(): Unit = {
notifier ! Register(self)
}
override def receive: Receive = {
case _ =>
}
}
case class Register(actor: ActorRef)
class MyActorSpec extends TestKit(ActorSystem("MyActorSpec")) with ImplicitSender with WordSpecLike with Matchers with BeforeAndAfterAll {
"MyActor" should {
val notifier = TestProbe()
"register itself in notifier" in {
val myActor = system.actorOf(Props(new MyActor(notifier.ref)))
notifier.expectMsg(Register(myActor))
}
}
}
The code you posted ideally should not even compile at:
val myActor = system.actorOf(Props(classOf[MyActor], notifier))
Because the constructor expects an ActorRef which we are not passing. But correcting it, it works:
class MyActorSpec extends TestKit(ActorSystem("MyActorSpec"))
with ImplicitSender
with WordSpecLike
with Matchers
with BeforeAndAfterAll {
"MyActor" should {
val notifier = TestProbe()
"register itself in notifier" in {
val myActor = system.actorOf(Props(classOf[MyActor], notifier.ref))
notifier.expectMsg(Register(myActor))
}
}
}
For a second, just to make sure that there is no special magic happening because of ActorProbe, I wrote plain old actor class below.
object Prac {
def main(args: Array[String]) {
val system = ActorSystem("HelloSystem")
val myActor = system.actorOf(Props(classOf[MainActor]))
}
}
class MyActor(notifier: ActorRef) extends Actor {
override def preStart(): Unit = {
notifier ! Register(self)
}
override def receive: Receive = {
case x => println("My Actor ->"+x)
}
}
case class Register(actor: ActorRef)
class MainActor extends Actor{
val actor = context.actorOf(Props(classOf[MyActor], self))
override def receive = {
case Register(x) =>
println(actor == x)
context.system.shutdown()
}
}
And it prints true. So there is nothing wrong with your programme.
I've figured it out. It was because I've used shared TestProbe in several test cases, in which I create different instances of MyActor.
class MyActorSpec extends TestKit(ActorSystem("MyActorSpec"))
with ImplicitSender
with WordSpecLike
with Matchers
with BeforeAndAfterAll {
"MyActor" should {
val notifier = TestProbe()
"register itself in notifier" in {
val myActor = system.actorOf(Props(classOf[MyActor], notifier.ref))
notifier.expectMsg(Register(myActor))
}
"do some useful work" in {
val myActor = system.actorOf(Props(classOf[MyActor], notifier.ref))
....
}
}
}
Instead, using a fresh instance of TestProbe for each test case helped.
class MyActorSpec extends TestKit(ActorSystem("MyActorSpec"))
with ImplicitSender
with WordSpecLike
with Matchers
with BeforeAndAfterAll {
"MyActor" should {
"register itself in notifier" in {
val notifier = TestProbe()
val myActor = system.actorOf(Props(classOf[MyActor], notifier.ref))
notifier.expectMsg(Register(myActor))
}
"do some useful work" in {
val notifier = TestProbe()
val myActor = system.actorOf(Props(classOf[MyActor], notifier.ref))
....
}
}
}
Anyway, thanks to all for proving that for single test case it works well.

Injecting Akka's TestProbe in place of child actors

I have a parent actor named "manager" which creates several child actors.
These child actors then send back their response via "sender tell", i.e directly back to "manager".
I want to create a unit test for this manager actor, and therefore need to inject a probe to forward the messages from the manager to its children.
I used the following post:
http://www.superloopy.io/articles/2013/injecting-akka-testprobe.html
However i'm still having some trouble getting this done correctly.
In order to simplify the situation, attached is code describing the actors and unit test i wrote for just one child.
Manager class:
trait ManagerChildProvider {
def createTimestampPointChild: Actor
}
trait ProductionManagerChildProvider extends ManagerChildProvider {
def createTimestampPointChild = new TimeDifferenceCalculationActor
}
object Manager {
def apply() = new Manager("cid1") with ProductionManagerChildProvider
}
class Manager(name: String) extends Actor with ActorLogging {
this: ManagerChildProvider =>
#Autowired private val modelParams = new ModelParams //list of parameters
val timeDifference = context.actorOf(Props(createTimestampPointChild))
def receive = {
case p#TimePoint(tPoint) =>
timeDifference ! p
case _ =>
log.error("Unknown message type")
}
}
Child class:
class TimeDifferenceCalculationActor extends Actor with ActorLogging {
var previousTimestamp: Long = -1
def receive = {
case tPoint(timestamp) =>
if (previousTimestamp != -1) {
sender ! Result(1)
}
case _ =>
log.error("Unknown message type")
}
}
Test class:
object BarSpec {
class Wrapper(target: ActorRef) extends Actor {
def receive = {
case x => target forward x
}
}
}
trait ChildrenProvider {
def newFoo: Actor
}
class BarSpec extends TestKitSpec("BarSpec") {
import Manager._
import BarSpec._
trait TestCase {
val probe = TestProbe()
trait TestChildrenProvider extends ManagerChildProvider {
def newBar = new Wrapper(probe.ref)
}
val actor = system.actorOf(Props(new Manager(componentId = "cid1") with TestChildrenProvider))
}
"Bar" should {
"involve child in doing something" in new TestCase {
actor ! tPoint(1)
actor ! tPoint(2)
probe.expectMsg(tPoint(1))
//probe.reply("ReplyFromChild")
//expectMsg("ReplyFromParent")
}
}
}
Additional test class:
abstract class TestKitSpec(name: String) extends TestKit(ActorSystem(name)) with MustMatchers with BeforeAndAfterAll with ImplicitSender with WordSpecLike{
override def afterAll() {
system.shutdown()
}
}
Currently i get the following errors:
Error:(36, 42) object creation impossible, since method > createTimestampPointChild in trait ManagerChildProvider of > type => akka.actor.Actor is not defined
val actor = system.actorOf(Props(new Manager(componentId = "cid1") with TestChildrenProvider))
Error:(11, 16) overriding method run in trait BeforeAndAfterAll of type > (testName: Option[String], args: > org.scalatest.Args)org.scalatest.Status;
method run in trait WordSpecLike of type (testName: Option[String], > args: org.scalatest.Args)org.scalatest.Status needs `abstract override' > modifiers
abstract class TestKitSpec(name: String) extends > TestKit(ActorSystem(name))
any help with these specific errors or with the task in general would be highly appreciated

Akka intercepting receive with stackable behavior

Akka and Scala newbie here, please feel free to edit the question as necessary in order to clearly articulate my intent in the domain of Scala and Akka.
Before I show code snippets, here's the problem I want to solve: I essentially want to develop a common module for my team to use when they're developing their applications using Akka actors. I want to allow them to mixin a trait which will extend their receive functionality at runtime, mainly for logging purposes. I'm running into compile errors, which I'll explain soon.
But first, take for example, a simple main:
object Test extends App {
val system = ActorSystem("system")
val myActor = system.actorOf(Props(new MyActor), "myActor")
myActor ! "Hello world!"
}
Here's an example implementation of an actor that a team member might implement in his application:
class MyActor extends Actor with ActorLogger {
override def receive: Receive = {
case msg => {
log.info("testing ...")
}
case _ => throw new RuntimeException("Runtime Ex")
}
}
And here's an example of how I would provide a common trait for them to mixin:
trait ActorLogger extends Actor {
val log: DiagnosticLoggingAdapter = Logging(this)
abstract override def receive: Receive = {
case msg: Any => {
if (msg.isInstanceOf[String]) {
println("enter")
log.mdc(Map[String, Any]("someKey" -> 123))
super.receive(msg)
log.clearMDC()
println("exit")
}
}
case _ => throw new RuntimeException("Runtime Ex")
}
}
As you can see, I'm trying to add data to an MDC if the message so happens to be String (a basic example, in reality, I would check for some custom type of our own).
The error I get is:
Error:(29, 16) overriding method receive in trait ActorLogger of type =>
MyActor.this.Receive;
method receive needs `abstract override' modifiers
override def receive: Receive = {
^
What's wrong here? And is stackable traits the right to go away to achieve something like this? If not, what is the most idiomatic way?
More generally, is there another pattern being applied here besides "interceptor" pattern?
Thanks for all the help!
A solution without a hack with akka package:
import akka.actor.{Actor, ActorSystem, Props}
trait MyActorExtension extends Actor {
def receiveExtension: Receive = PartialFunction.empty
}
abstract class MyActor extends MyActorExtension {
protected def receiveMsg: Receive
def receive: Receive = receiveExtension orElse receiveMsg
}
trait ActorLogger1 extends MyActor with MyActorExtension {
abstract override def receiveExtension = {
case msg =>
println(s"********** Logging # 1: $msg")
super.receiveExtension.applyOrElse(msg, receiveMsg)
}
}
trait ActorLogger2 extends MyActor with MyActorExtension {
abstract override def receiveExtension = {
case msg =>
println(s"########## Logging # 2: $msg")
super.receiveExtension.applyOrElse(msg, receiveMsg)
}
}
class SpecificActor extends MyActor with ActorLogger1 with ActorLogger2 {
def receiveMsg = {
case someMsg =>
println(s"SpecificActor: $someMsg")
}
}
object Test extends App {
val system = ActorSystem("system")
val mySpecificActor = system.actorOf(Props(new SpecificActor), "SpecificActor")
mySpecificActor ! "Hello world!"
}
#### Logging # 2: Hello world!
****** Logging # 1: Hello world!
SpecificActor: Hello world!
aroundReceive is for Akka internal use and the stackable trair pattern is not that comfortable for this case.
I recommend you using Receive Pipeline for easy message interception.
I think that you need something like this
package akka
import akka.MsgsProt._
import akka.actor.{ Actor, ActorSystem, Props }
import scala.concurrent.duration._
sealed trait MsgProt
object MsgsProt {
case object FooMsg extends MsgProt
case object BarMsg extends MsgProt
}
trait Foo extends Actor {
override protected[akka] def aroundReceive(receive: Actor.Receive, msg: Any): Unit = msg match {
case FooMsg => println("Foo message")
case msg => super.aroundReceive(receive, msg)
}
}
trait Bar extends Actor {
override protected[akka] def aroundReceive(receive: Actor.Receive, msg: Any): Unit = msg match {
case BarMsg => println("Bar message")
case msg => super.aroundReceive(receive, msg)
}
}
class MyActor extends Actor with Foo with Bar {
override def receive: Actor.Receive = {
case _ => println("Nothing I know")
}
}
object Foo extends App {
val system = ActorSystem("foobar")
val myActor = system.actorOf(Props[MyActor])
implicit val timeout = 2 seconds
myActor ! FooMsg
myActor ! BarMsg
myActor ! "wrong message"
system.awaitTermination(10 seconds)
}
The output of this program is:
Foo message
Bar message
Nothing I know
Most important part is that package declaration - akka. Because method aroundReceive is limited only to akka package so you have to have some.package.akka and inside you can use that method aroundReceive. I think that it looks more like a hack not a solution but works. You can see more usage of this inside Akka itself ex. akka.DiagnosticActorLogging. But this is basically solution that you want to do with stacking Actors behaviour.

How to start a Scala akka actor

Below class is causing an error at line new HelloWorld :
Exception in thread "main" akka.actor.ActorInitializationException: You cannot create an instance of [HelloWorld] explicitly using the constructor (new). You have to use one of the 'actorOf' factory methods to create a new actor. See the documentation.
at akka.actor.ActorInitializationException$.apply(Actor.scala:219)
at akka.actor.Actor$class.$init$(Actor.scala:436)
at HelloWorld.<init>(HelloWorld.scala:4)
at Driver$.main(HelloWorld.scala:38)
at Driver.main(HelloWorld.scala)
So I try : val hw = actorOf(new HelloWorld)
But this causes a compiler error :
not found: value actorOf
How should HelloWorld below be implemented ?
Reading other Scala docs an act method is requried to be defined within the class that extends Actor and then invoke the start method on this class, is there a reason for using actorOf instead of defining an act method ?
Below class is taken from Scala akka docs http://doc.akka.io/docs/akka/2.2.0/scala.html :
import akka.actor.Actor
import akka.actor.Actor._
import akka.actor.Props
class HelloWorld extends Actor {
override def preStart(): Unit = {
// create the greeter actor
val greeter = context.actorOf(Props[Greeter], "greeter")
// tell it to perform the greeting
greeter ! Greeter.Greet
}
def receive = {
// when the greeter is done, stop this actor and with it the application
case Greeter.Done => context.stop(self)
}
object Greeter {
case object Greet
case object Done
}
class Greeter extends Actor {
def receive = {
case Greeter.Greet =>
println("Hello World!")
sender ! Greeter.Done
}
}
}
object Driver {
def main(args: Array[String]) {
new HelloWorld
}
}
You need to edit your main as shown below. Secondly, in line-5, you need to change it to context.actorOf(Props(new Greeter)). This is because your Greeter does not have apply function defined, hence you need to manually create Greeter object yourself.
Working code below:
import akka.actor.ActorSystem
class HelloWorld extends Actor {
override def preStart(): Unit = {
// create the greeter actor
val greeter = context.actorOf(Props(new Greeter), "greeter")//line 5
// tell it to perform the greeting
greeter ! Greeter.Greet
}
def receive = {
// when the greeter is done, stop this actor and with it the application
case Greeter.Done => context.stop(self)
}
object Greeter {
case object Greet
case object Done
}
class Greeter extends Actor {
def receive = {
case Greeter.Greet =>
println("Hello World!")
sender ! Greeter.Done
}
}
}
object Driver {
def main(args: Array[String]) {
val system = ActorSystem("Main")
val ac = system.actorOf(Props[HelloWorld])
}
}
If you want to use your main class do the following:
import akka.actor.{ActorSystem, Props}
object Driver extends App {
val system = ActorSystem("System")
val hw = system.actorOf(Props[HelloWorld], name = "hw")
}
Which will create a new actor system and then create the HelloWorld actor using that actor system.
You can also follow the akka instructions:
set Akka.Main as the main class and give the program "com.example.HelloWorld" as argument.
val greeter = context.actorOf(Props(new Greeter), "greeter")//line 5
I don't think you need to have a new keyword there for Greeter. I believe the Props does that for you already. If anything having a new should be a