Hi Lawrence,

you don’t need to pass around ActorContext: just return the Props to the actor 
and call context.actorOf() there. Passing around ActorContext is not something 
that should be handled with caution, it is a recipe for disaster and will 
result in weird failures eventually; the reason is that because of the Actor 
Model you or your team will think that low-level synchronization is not an 
issue, and keeping only exactly this one type separate is tedious and 
error-prone.

When it comes to testing I recommend functional tests only (message in, 
message(s) out), no verification of meaningless details such as passing an 
implementation detail to some mock—that will only break once you improve your 
implementation and thereby create extra work and impede progress. In the case 
at hand you would give a Props-factory to your Actor (the FulfilRegistration 
class with my suggested modification) and during test you can have that inject 
the right stub actors quite naturally.

Regards,

Roland

28 maj 2014 kl. 18:00 skrev Lawrence Wagerfield <lawre...@dmz.wagerfield.com>:

> I had an Actor whose code grew to be quite large, so this is the result of a 
> refactoring.
> 
> The new class performs actions on behalf of the actor, impersonating it, so 
> to speak. It caries out various send operations, sets up state with 
> un/become, etc.
> 
> The refactor produces clearer and more testable code, although I do 
> appreciate why ActorContext (or any other internal state) should be handled 
> with caution.
> 
> My code is as follows:
> (note: CheckEmailAddressAvailability follows a similar pattern - code omitted 
> as you'll already get the idea!)
> 
> class UserRegistry(fulfilRegistration: FulfilRegistration) extends 
> EventsourcedProcessor {
>   override def receiveRecover: Receive = {
>     case UserSubmittedRegistration(registration) =>
>       fulfilRegistration(registration)
>   }
> 
>   override def receiveCommand: Receive = {
>     case registrationEvent: UserSubmittedRegistration =>
>       persist(registrationEvent) { event =>
>         fulfilRegistration(event.registration)
>       }
>   }
> }
> 
> trait FulfilRegistration {
>   def apply(registration: Registration)(implicit context: ActorContext): Unit
> }
> 
> class FulfilRegistrationImpl(implicit checkEmailAddressAvailability: 
> CheckEmailAddressAvailability)
>   extends FulfilRegistration{
>   def apply(registration: Registration)(implicit context: ActorContext): Unit 
> =
>     FulfilRegistration
>       .beginTransaction(registration)
> }
> 
> object FulfilRegistration {
>   def beginTransaction(registration: Registration)(implicit context: 
> ActorContext, checkEmailAddressAvailability: CheckEmailAddressAvailability): 
> Unit = {
>     val name = transactionActorName(registration.newUserId)
>     val actorRef = context.actorOf(transactionProps, name)
>     actorRef forward registration
>   }
> 
>   def transactionActorName(userId: UserId): String =
>     userId.toString
> 
>   private def transactionProps(implicit checkEmailAddressAvailability: 
> CheckEmailAddressAvailability): Props =
>     Props(new RecoverableActor {
>       override protected def initialState: Receive = notRegistered
> 
>       override def receiveRecover: Receive = {
>         case UserRegistered() =>
>           context stop self
> 
>         case RegistrationDeniedDueToDuplicateEmail() =>
>           context stop self
>       }
> 
>       private def notRegistered: Receive = {
>         case Registration(newUserId, _, EmailCredential(emailAddress, _)) =>
>           val registrant = sender()
> 
>           def allowRegistration(): Unit = {
>             val event = UserRegistered()
>             registrant ! event // Informing registrant is part of the 
> registration so occurs before committing the event.
>             persist(event) { _ =>
>               context stop self
>             }
>           }
> 
>           def denyRegistration(): Unit = {
>             val event = RegistrationDeniedDueToDuplicateEmail()
>             registrant ! event // Informing registrant is part of the denial 
> so occurs before committing the event.
>             persist(event) { _ =>
>               context stop self
>             }
>           }
> 
>           checkEmailAddressAvailability(emailAddress) { emailAddressAvailable 
> =>
>             if (emailAddressAvailable)
>               allowRegistration()
>             else
>               denyRegistration()
>           }
>       }
>     })
> }
> 
> 
> On Wednesday, May 28, 2014 4:45:52 PM UTC+1, Konrad Malawski wrote:
> We strongly advertise against exposing your ActorContext - it's scary what 
> could happen with it being accessed from outside of the respective actor.
> 
> What's your use case? Perhaps there is a better way to test / abstract it?
> 
> 
> On Wed, May 28, 2014 at 4:56 PM, Lawrence Wagerfield 
> <lawr...@dmz.wagerfield.com> wrote:
> Hi Konrad,
> 
> I'm currently using TestActorRef to obtain the underlying ActorContext. I am 
> using this to assert the actor is passing its own context as an argument to a 
> mocked-out dependency.
> 
> Can you think of another way using existing TestKit probes, or is this the 
> best way?
> 
> Thanks,
> Lawrence
> 
> 
> 
> On Wednesday, May 28, 2014 3:48:26 PM UTC+1, Konrad Malawski wrote:
> Hello Lawrence,
> Because of the processor’s inner workings (how it interacts with the Journal) 
> it does not make sense to test it using the synchronous test utilities (such 
> as TestActorRef).
> Please do not use TestActorRef with Akka-Persistence - use the plain TestKit 
> and it’s probes and other utils.
> 
> // We had such issue reported, and marked as won’t fix 
> https://github.com/akka/akka/issues/15293
> 
> ​
> 
> 
> On Wed, May 28, 2014 at 4:20 PM, Lawrence Wagerfield 
> <lawr...@dmz.wagerfield.com> wrote:
> Using TestActorRef on implementations of Processor (and 
> EventsourcedProcessor) appears to introduce a deadlock at the point of 
> calling into the snapshot store actor.
> 
> The result is an actor-under-test that never completes recovery.
> 
> I have worked-around this issue by providing 
> .withDispatcher(Dispatchers.DefaultDispatcherId) on the Props object I 
> construct the TestActorRef with.
> 
> Should I raise this as an issue? Currently using Akka 2.3.3.
> 
> -- 
> >>>>>>>>>> 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 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.
> 
> 
> 
> -- 
> Cheers,
> Konrad 'ktoso' Malawski
> hAkker - Typesafe, Inc
> 
> 
> 
> -- 
> >>>>>>>>>> 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 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.
> 
> 
> 
> -- 
> Cheers,
> Konrad 'ktoso' Malawski
> hAkker - Typesafe, Inc
> 
> 
> 
> -- 
> >>>>>>>>>> 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 the Google Groups 
> "Akka User List" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to akka-user+unsubscr...@googlegroups.com.
> To post to this group, send email to akka-user@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


-- 
>>>>>>>>>>      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 the Google Groups "Akka 
User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to akka-user+unsubscr...@googlegroups.com.
To post to this group, send email to akka-user@googlegroups.com.
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.

Reply via email to