why actors are not POSO's?

109 views
Skip to first unread message

Kostas kougios

unread,
Jun 10, 2015, 4:09:18 PM6/10/15
to akka...@googlegroups.com
In the other thread of mine, I explained a testability issue I have with actors which require complex messaging. But also a good question is, why are not actors POSO's? It would increase testabilty & maintainability.

Richard Bradley

unread,
Jun 16, 2015, 9:35:14 AM6/16/15
to akka...@googlegroups.com
How could they be?

I take it that by "POSO" you mean that an Actor would not need to implement any traits? How would the framework get such an Actor to receive a message, as there would be no guarantee that the object implemented a "receive" method?

Konstantinos Kougios

unread,
Jun 16, 2015, 9:57:05 AM6/16/15
to akka...@googlegroups.com
ok,maybe POSO is not possible. But if I understand correctly, the only basic requirement for an actor is an Actor.Receive (a partial function).

The main "issue" is that actors extends Actor (which is nice and proper in terms of class hierarchy) with actor containing fields context, self, sender() etc. That's nice and convenient but it creates a few testability issues. i.e.

class MyActor extends Actor {
    private val child=context.actorOf(....)
...
    child ! "hi" // how to test the communication between MyActor and child?
}

The need for "TestKit", even for unit tests, tells me that a bit of refactoring could help. Ideally, at least for the unit tests, testing should be done without any such dependency, only mocks. Martynas pointed out the prototype Akka-Typed (http://doc.akka.io/docs/akka/snapshot/scala/typed.html) which I need to have a look .

Note, when I talk about actor testing, I always mean message flow testing (the business logic can be extracted to separate POSO classes)
--
>>>>>>>>>> Read the docs: http://akka.io/docs/
>>>>>>>>>> Check the FAQ: http://doc.akka.io/docs/akka/current/additional/faq.html
>>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
---
You received this message because you are subscribed to a topic in the Google Groups "Akka User List" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/akka-user/QM6Y69oYECM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to akka-user+...@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.

Richard Bradley

unread,
Jun 16, 2015, 10:08:55 AM6/16/15
to akka...@googlegroups.com
> ok,maybe POSO is not possible. But if I understand correctly, the only basic requirement for an actor is an Actor.Receive (a partial function).

Yes, and if you look in the akka.actor.Actor trait, that's the only abstract method required by that trait.

> The main "issue" is that actors extends Actor (which is nice and proper in terms of class hierarchy) with actor containing fields context, self, sender() etc. That's nice and convenient but it creates a few testability issues. i.e.

They mix in the trait, rather than extending a subclass.

Your example doesn't demonstrate any problem with subclasses v.s. POSOs.
If I change the example code to be a POSO, there is still the exact same problem:

class MyParentPoso {
    private val child = new ChildPoso()
...
    child.say("hi") // how to test the communication between MyParentPoso and child?
}

Your example is one where Dependency Injection (rather than having the parent create its own collaborator) will lead to testable code:

class MyActor(collaborator: ActorRef) extends Actor {
   ...

   collaborator ! "hi" // now you can test the communication
}


Hope this helps,


Rich

Konstantinos Kougios

unread,
Jun 16, 2015, 11:16:27 AM6/16/15
to akka...@googlegroups.com
Hi,


On 16/06/15 15:08, Richard Bradley wrote:
> ok,maybe POSO is not possible. But if I understand correctly, the only basic requirement for an actor is an Actor.Receive (a partial function).

Yes, and if you look in the akka.actor.Actor trait, that's the only abstract method required by that trait.
but it also contains the context, sender etc which as soon as MyActor extends Actor, they can't be easily mocked.



> The main "issue" is that actors extends Actor (which is nice and proper in terms of class hierarchy) with actor containing fields context, self, sender() etc. That's nice and convenient but it creates a few testability issues. i.e.

They mix in the trait, rather than extending a subclass.

Your example doesn't demonstrate any problem with subclasses v.s. POSOs.
If I change the example code to be a POSO, there is still the exact same problem:

class MyParentPoso {
    private val child = new ChildPoso()
...
    child.say("hi") // how to test the communication between MyParentPoso and child?
}

Your example is one where Dependency Injection (rather than having the parent create its own collaborator) will lead to testable code:

class MyActor(collaborator: ActorRef) extends Actor {
   ...

   collaborator ! "hi" // now you can test the communication
}

In fact that's what I did in my project. I got a trait ActorExt which basically is Actor.Receive. My actor is like

class MyActor(actorDetails:ActorDetails) extends ActorExt {
private val child = actorDetails.actorOf(...)
 val receive = {
    case ....=>
}
}

Then I mock actorDetails.actorOf. (also I can mock actorDetails.sender , actorDetails.self etc)


Cheers

Ryan Tanner

unread,
Jun 16, 2015, 11:35:49 AM6/16/15
to akka...@googlegroups.com
That approach sounds dangerous.  You shouldn't leak context outside of the actor, so where is actorDetails getting those?

Personally I think needing to mock sender, self, etc. is a code smell.  

Konstantinos Kougios

unread,
Jun 16, 2015, 11:43:46 AM6/16/15
to akka...@googlegroups.com
Hmm, context is not leaking, maybe from my example it is not obvious what is actually going on in the code.

Why mocking i.e. sender is code smell (for unit tests)?

Roland Kuhn

unread,
Jun 17, 2015, 9:50:38 AM6/17/15
to akka-user
16 jun 2015 kl. 17:43 skrev 'Konstantinos Kougios' via Akka User List <akka...@googlegroups.com>:

Hmm, context is not leaking, maybe from my example it is not obvious what is actually going on in the code.

Why mocking i.e. sender is code smell (for unit tests)?

Why would you need special tricks to mock the sender of a message? You can just provide the sender’s ActorRef explicitly in the `.tell()` invocation.

While I appreciate that this is probably contentious my opinion is that mocking (in the magic sense, where stubs are created by waving the bytecode wand) is always a sign of a lack of proper tooling. And even with DI it tells you something about your code if writing tests for a single component requires a large amount of mocking and setup code—that component is quite likely too tightly coupled with too many other things.

Akka’s main purpose is to model distribution and provide the tools for efficient formulation of distributed components. An Actor is precisely that—an isolated location-transparent agent—and therefore we have the TestKit for allowing an Actor to interact with a fabricated test environment. You could say that TestProbe is the only (and universal) mock you’ll ever need for testing Actors. The reasoning is that since Actors are encapsulated and only communicate via messages it makes no sense to test them in a different way; in this regard I regret convincing Viktor of the necessity of the TestActorRef some four years ago. The motivation was not to allow tests to introspect the Actor, it was conceived only to provide a way to get the Actor quickly into the starting condition required for the test case.

Now, with Akka Typed all these issues are being addressed: Behaviors can freely be created (also in non-initial states) and in addition to putting them inside an ActorContext they can also be run fully synchronously for test purposes in different context implementations. Still, the only (universal) mock needed to simulate interlocutors is the correspondent of TestProbe which is now called Inbox.sync[T].

Regards,

Roland

You received this message because you are subscribed to the Google Groups "Akka User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to akka-user+...@googlegroups.com.

To post to this group, send email to akka...@googlegroups.com.
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.



Dr. Roland Kuhn
Akka Tech Lead
Typesafe – Reactive apps on the JVM.
twitter: @rolandkuhn


Konstantinos Kougios

unread,
Jun 17, 2015, 10:18:32 AM6/17/15
to akka...@googlegroups.com
hmm, maybe I need to, later on, put a small example into place to better see what usecase might be wrong or not.

I suppose creating a child actor within an actor is a typical use case and we need to be able to easy test it. Also self ! Msg too as it is i.e. required when actorSelector(...).resolveOne(... a future that self ! msg  to avoid sync issues). My most complex use case is one of my server-actors receiving a msg from a driver-actor, all cluster server-actors must be informed about this message and upon confirmation the server-actor can complete this transaction.


some more answers below:


On 17/06/15 14:50, Roland Kuhn wrote:

16 jun 2015 kl. 17:43 skrev 'Konstantinos Kougios' via Akka User List <akka...@googlegroups.com>:

Hmm, context is not leaking, maybe from my example it is not obvious what is actually going on in the code.

Why mocking i.e. sender is code smell (for unit tests)?

Why would you need special tricks to mock the sender of a message? You can just provide the sender’s ActorRef explicitly in the `.tell()` invocation.
sure , but the typical use case is to use the sender(). Avoiding that, solves this issue.


While I appreciate that this is probably contentious my opinion is that mocking (in the magic sense, where stubs are created by waving the bytecode wand) is always a sign of a lack of proper tooling. And even with DI it tells you something about your code if writing tests for a single component requires a large amount of mocking and setup code—that component is quite likely too tightly coupled with too many other things.
I agree (for the large scale mocking which shows problems in the design). But what is wrong say if we could magically mock the child actor and then:

val childActor=mock[ActorRef] // ... and magically this is visible via our actor

actor ! Msg // this should make the actor do something and then to childActor ! AnOtherMsg

verify(childActor ! AnOtherMsg )

Cheers

Roland Kuhn

unread,
Jun 17, 2015, 10:33:08 AM6/17/15
to akka-user
17 jun 2015 kl. 16:18 skrev 'Konstantinos Kougios' via Akka User List <akka...@googlegroups.com>:

hmm, maybe I need to, later on, put a small example into place to better see what usecase might be wrong or not.

I suppose creating a child actor within an actor is a typical use case and we need to be able to easy test it. Also self ! Msg too as it is i.e. required when actorSelector(...).resolveOne(... a future that self ! msg  to avoid sync issues). My most complex use case is one of my server-actors receiving a msg from a driver-actor, all cluster server-actors must be informed about this message and upon confirmation the server-actor can complete this transaction.

Replacing the Cluster extension during tests is currently not possible, that is indeed a hole that could be plugged.



some more answers below:

On 17/06/15 14:50, Roland Kuhn wrote:

16 jun 2015 kl. 17:43 skrev 'Konstantinos Kougios' via Akka User List <akka...@googlegroups.com>:

Hmm, context is not leaking, maybe from my example it is not obvious what is actually going on in the code.

Why mocking i.e. sender is code smell (for unit tests)?

Why would you need special tricks to mock the sender of a message? You can just provide the sender’s ActorRef explicitly in the `.tell()` invocation.
sure , but the typical use case is to use the sender(). Avoiding that, solves this issue.

val p = TestProbe()
actor.tell(Message(...), p.ref)
// now within actor the sender() will be p.ref, no mocking needed


While I appreciate that this is probably contentious my opinion is that mocking (in the magic sense, where stubs are created by waving the bytecode wand) is always a sign of a lack of proper tooling. And even with DI it tells you something about your code if writing tests for a single component requires a large amount of mocking and setup code—that component is quite likely too tightly coupled with too many other things.
I agree (for the large scale mocking which shows problems in the design). But what is wrong say if we could magically mock the child actor and then:

val childActor=mock[ActorRef] // ... and magically this is visible via our actor

actor ! Msg // this should make the actor do something and then to childActor ! AnOtherMsg

verify(childActor ! AnOtherMsg )

Right, this will all be completely natural with the EffectfulActorContext in Akka Typed (where spawn() just creates Inbox.sync and `self` also returns such an Inbox.sync). Until then the solution is to factor out the creation of child actors (or in general how to obtain other ActorRefs) into a separate trait (for Scala) or factory object (for Java). Then you can easily inject TestProbes during tests.

Regards,

Roland
Reply all
Reply to author
Forward
0 new messages