I will take a look at the ScalaDoc for ActorRefImpl.
To answer your question about how I intend to test behaviors, let me 
clarify that my concern was not about testing behaviors specifically.
I was starting out by testing my interactions with behaviors.
Hopefully I can illustrate what I mean with a couple of examples below.
As you can see in FooApp, it is trivially easy for me to test interactions 
with an ActorRef if it does not have a self type constraint.
As you can see in BarApp, the self-type forces me to add another level of 
indirection in the form of ActorRefContract and ActorRefDelegate.
My initial impression is that this is unnecessary complexity that could 
have been designed away by a "design by contract" approach.
Alternatively, ActorRef could be made to extend another trait without a 
self type, and all interactions with actors could be through that trait 
instead of through an ActorRef.
Hopefully this clarifies where my initial design concern is.

import scala.collection.mutable.ArrayBuffer

object FooApp extends App {

  trait ActorRef[T] {
    def !(msg: String): Unit
  }

  class Coordinator(greeter: ActorRef[String]) {
    def newcomer(name: String): Unit = {
      greeter ! name
    }
  }

  class ActorRefStub extends ActorRef[String] {
    val messagesSent = new ArrayBuffer[String]()

    override def !(msg: String): Unit = messagesSent.append(msg)
  }

  def assertEquals[T](caption: String, actual: T, expected: T): Unit = {
    if (actual == expected) println(s"SUCCESS($caption)")
    else println(s"FAILURE($caption): expected $expected, got $actual")
  }

  // given
  val actorRefStub = new ActorRefStub()
  val coordinator = new Coordinator(actorRefStub)

  // when
  coordinator.newcomer("world")

  // then
  assertEquals("exactly one message sent", actorRefStub.messagesSent.size, 1)
  assertEquals("the right message was sent", actorRefStub.messagesSent(0), 
"world")

  /* output
  SUCCESS(exactly one message sent)
  SUCCESS(the right message was sent)
   */
}


import akka.typed.ActorRef

import scala.collection.mutable.ArrayBuffer

object BarApp extends App {

  trait ActorRefContract[T] {
    def !(msg: T): Unit
  }

  class ActorRefDelegate[T](delegateToMe: ActorRef[T]) extends 
ActorRefContract[T] {
    override def !(msg: T): Unit = delegateToMe ! msg
  }

  class Coordinator(greeter: ActorRefContract[String]) {
    def newcomer(name: String): Unit = {
      greeter ! name
    }
  }

  class ActorRefStub extends ActorRefContract[String] {
    val messagesSent = new ArrayBuffer[String]()

    override def !(msg: String): Unit = messagesSent.append(msg)
  }

  def assertEquals[T](caption: String, actual: T, expected: T): Unit = {
    if (actual == expected) println(s"SUCCESS($caption)")
    else println(s"FAILURE($caption): expected $expected, got $actual")
  }

  // given
  val actorRefStub = new ActorRefStub()
  val coordinator = new Coordinator(actorRefStub)

  // when
  coordinator.newcomer("world")

  // then
  assertEquals("exactly one message sent", actorRefStub.messagesSent.size, 1)
  assertEquals("the right message was sent", actorRefStub.messagesSent(0), 
"world")

  /* output
  SUCCESS(exactly one message sent)
  SUCCESS(the right message was sent)
   */
}


On Wednesday, August 16, 2017 at 11:28:44 PM UTC-7, rkuhn wrote:
>
> Hi Sean,
>
> thanks for discussing Akka Typed!
>
> The design decision behind splitting the interface into a public and a 
> private part is documented in the ScalaDoc for ActorRefImpl: end users 
> shall not ever see the top two methods because there cannot possibly be a 
> reason to use them—but the implementation will need them. Therefore I felt 
> that internals are leaked by having just one interface. Another (minor) 
> issue is that equality and toString are fixed by the semantics of the 
> interface and the self-type ensures that this contract is not broken.
>
> Thankfully, the whole design of Akka Typed is much different from untyped 
> Akka, where this kind of separation was forced by implementation details. 
> In Akka Typed we are free to fold ActorRefImpl into ActorRef and revert the 
> decision. We should then make ActorRef an abstract class, so that it can 
> also safely be used from Java without losing the semantic contract. The 
> downside would remain: exposing methods that don’t belong into user space.
>
> May I ask in how far your intended ActorRef implementation would be 
> different from TestProbe or Inbox? Since there is only a single purpose to 
> ActorRef—sending single messages—we should be able to include all needed 
> stub functionality in one implementation; my guess is that your 
> fake/stub/mock would reimplement what is already there but I may well be 
> missing something.
>
> Another point that I’d like to hear more about is how you intend to test 
> your behaviors in general. This question stems from some surprise at 
> hearing “hard to test” in conjunction with Akka Typed :-) (given that 
> testability is an explicit design goal)
>
> Regards,
>
> Roland
>
> 16 aug. 2017 kl. 21:05 skrev Sean Shubin <[email protected] <javascript:>
> >:
>
> ActorRef has a self type of ActorRefImpl.  This means that if I want to 
> fake/stub/mock an ActorRef for test purposes, I cannot because I am forced 
> to know about ActorRefImpl.  Instead of users of ActorRef being forced to 
> only use the ActorRefImpl implementation, ActorRef should be a minimal 
> interface that only exposes the essential characteristics of an ActorRef, 
> freeing up users to chose among implementations of ActorRef, including 
> fakes/stubs/mocks for testing, and an ActorRefImpl for production.  As it 
> is designed now, I don't see how one can easily test akka.typed code 
> without specialized libraries that know about ActorRefImpl.
>
> I find that hard to test code is usually a result of design decisions 
> rather than the inherent nature of the problem, and with careful attention 
> and imagination one can make code easy to test without having to use a 
> specialized library.
>
> I am just starting to learn akka typed, so hopefully I will have time to 
> give more detailed feedback than just the one example once I am more 
> familiar with the design.  I am hoping that before removing the warning 
> about how the akka.typed API and semantics may change, the design is 
> refactored to support a more test driven, design by contract approach.  I 
> love the idea of having a statically typed, event driven option for how I 
> code, so am really glad akka.typed is being worked on.
>
>
> -- 
> >>>>>>>>>> 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 [email protected] <javascript:>.
> To post to this group, send email to [email protected] 
> <javascript:>.
> Visit this group at https://groups.google.com/group/akka-user.
> For more options, visit https://groups.google.com/d/optout.
>
>
>

-- 
>>>>>>>>>>      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 [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.

Reply via email to