I'm exploring Macwire DI framework for Scala and while doing it I faced a problem.
I have a dispatcher actor that creates a bunch of actors that are dependent on the dispatcher. Dispatcher controls all the message flow between its child actors.
Here's a brief situation of my setup:
class WorkerActor(dispatcher: ActorRef) extends Actor {}
class Dispatcher extends Actor {
private val worker = context.actorOf(Props(
new WorkerActor(self)
))
}
In my real project WorkerActor has more dependencies than only one “self”. And they can be easily wired.
I tried doing this dispatcher: ActorRef ## Dispatcher, but it gave me error:
Error:(47, 9) Cannot find a value of type: [akka.actor.ActorRef ##
Dispatcher]
wire[WorkerActor]
If I was using guice, this would work like a charm:
bind[AkkaRef] annotatedWith(Names.named("Dispatcher")) toInstance self
The question is: how do I add “self” to the scope of macwire?
Or maybe I should use different approach?
Thanks!
Related
Module code in common-project shared via jar and I wish to change internal dependency in compile time
trait MyTableNames
trait MyDAO extends MyTableNames
trait ActorService {
def send(actorMessage: Any) = println("sending message... will reach some Actor and then from actor to DAO")
}
trait MyActor extends MyDAO
object SaveUserActorMessage
trait MyService extends ActorService {
def addUser() = send(SaveUserActorMessage) // Not aware of dao just sends a message so service is disconnected from DAO.
}
A different server code using common-project via it's shared jar
The client code who uses this service only creates the service.
The problem is that I need to "inject" some other implementation of MyTableNames
from a different project which reuses the common-project above:
trait MyOwnTableNames extends MyTableNames
class MyCustomService extends MyService {
def someOtherAddUser() = addUser() // How do I tell the DAO which the service does not have a direct reference to, to use MyOwnTableNames, in compile time right now as a client code, I only have reference to MyService. In addition MyService has no direct relation to MyDAO it's only has a relation to ActorService which has no direct relation to DAO only the end actor which processes the message has a reference to DAO.
}
Please note: This example my not look "beautiful" and is not strickly cake pattern, I had to make it so so that I could compact it to a few lines of code, the bottom line is that my client code references a service and does an operation on service, the service then sends a message to actor, and the end actor uses a DAO, my problem is that the DAO at the end is trying to refer to MyTableNames which I want to replace. I use clean scala code, No DI framework, I prefer to avoid implicits and only use cake pattern if possible.
You could rely on Scala's linearization to order traits correctly and simply do
class MyCustomService extends MyService with MyOwnTableNames
There's a small caveat here. If anything that extends MyTableNames uses some value of MyTableNames in a val, you can get an NPE due to class initialization ordering issues. To fix that you would have to either use lazy val or def.
First of all, I am not asking how to unit test an Akka Actor. I know the techniques to do that. My problem is slightly different.
I am developing a Scala program, let's call it the client, that does not use Akka Actors. However, the program uses a library, let's call it the server, whose interface is implemented using an Akka Actor.
Then, through the ask pattern, the client interacts with the server.
// This is the client program
class Client(uri: String) {
implicit val context: ActorSystem = ActorSystem("client-actor-system")
private val mainActor = context.actorSelection(uri)
def connect: Future[SomeClass] = {
implicit val timeout: Timeout = Timeout(5 seconds)
(mainActor ? Connect()).mapTo[CreationResponse]
}
}
Now, I want to write down some unit tests for Client class. Unit testing means to test a class in isolation. Every external dependency should be mocked.
How can I mock the reference to mainActor inside Client class? How can I inject in the actor system a mock actor for mainActor?
Thanks in advance.
I would inject the mainActor actor selection into the client, and create that using Akka TestKits.
Of course, you need an ActorSelection, not an ActorRef. Some solutions for that can be found here:
Giving an ActorPath for a testProbe
Or alternatively, you could make mainActor an ActorRef by sending an Identify message to the ActorSelection.
I'm trying to test an Actor A inside my Play 2.4 application with Scaldi. This actor is calling injectActorRef[B] that I want to mock with a TestKit.TestProbe.
Inside my specs2, I would like to be able to retrieve the probe for mocked B while providing the corresponding TestKit.TestProbe.ref to actor A.
I would like to do something like this :
implicit val inj = (new TestModule(){
bind[TestProbe] identifiedBy 'probeForB to TestProbe()
bind[B] to inject[TestProbe]('probeForB).ref
}).injector
inject[TestProbe]('probeForB).expectMsgType[] must ...
The issue is that the ref is an ActorRef and therefore does not match the expected Btype.
Is there a clean way to do that ?
Can we specify an ActorRef to be returned by injectActorRef[B]?
I ended up overriding the bind for Actor A.
val probeForB = TestProbe()
implicit val inj = (new Module() {
bind[A] to new A() {
override def injectB(): ActorRef = probeForB.ref
}
}).injector
As you mentioned, the issue is that inject[TestProbe]('probeForB).ref gives you an ActorRef back instead of an instance of actual actor.
If you would like to test it in a way you described, then you need define a binding of ActorRef for actor B as well. For example:
bind [BActor] toProvider new BActor
bind [ActorRef] identifiedBy 'bRef to {
implicit val system = inject [ActorSystem]
injectActorRef[BActor]
}
When you have this setup, then you can override the second binding with test probe:
bind [ActorRef] identifiedBy 'bRef to inject[TestProbe]('probeForB).ref
Please note, that this example is not direct equivalent since BActor now has a different supervisor (guardian actor, that's why we need to inject an ActorSystem here).
injectActorRef delegates an actor creation to a "context" (a parent actor or actor system) with context.actorOf. What makes it helpful is that it creates a special Props that injects new instances of BActor class when akka wants to create one. This means that scaldi does not have control over the actor lifecycle (it's pretty important, since akka itself has very sophisticated mechanisms for this), it just gives akka the knowledge how to create new instances of particular actor class.
If you are creating an actor within another actor (like you described), then the lifecycle of them both is strongly connected and managed by akka. That's the reason why in this case you can't simply override and Actor binding with an ActorRef binding for the tests.
I wish to use the scheduler of akka, the examples are saying:
system.scheduler.scheduleOnce()
but there is no real information where the "system" should come from. The documentation is a little bit superficial and there was a lot of change (akka moved out of core scala).
If I write
val system = akka.actor.ActorSystem("system")
I will have a ActorSystem, but it will be a new independent ActorSystem with around 8 new threads. I think, that this is an overkill for a small scheduler and not really recommended.
How can I just re-use the existing system of play framework 2 ?
Thanks
To get hands on the default actor system defined by Play you have to import the play.api.libs.concurrent.Akka helper.
Akka.system will be a reference to the default actor system, and then you can do everything with it as you would do with an actor system created by yourself:
import play.api.libs.concurrent.Akka
val myActor = Akka.system.actorOf(Props[MyActor], name = "myactor")
Akka.system.scheduler.scheduleOnce(...)
update:
The above static methods became deprecated in Play 2.5 and was removed in 2.6, so now you have to use dependency injection.
In Scala:
class MyComponent #Inject() (system: ActorSystem) {
}
In Java:
public class MyComponent {
private final ActorSystem system;
#Inject
public MyComponent(ActorSystem system) {
this.system = system;
}
}
When you use play.api.libs.concurrent.Akka you are using the actor system created by play. In fact that is the way encouraged.
You can read that in the documentation.
I am doing a web application with Scala and Akka actors and I'm having some troubles with the tests.
In my case I need to taste an actor who talks with the Database. To do the unit testing I would like to use a Fake Database but I can't replace the new with my desired fake object.
Let's see some code:
Class MyActor extends Actor {
val database = new Database()
def receive = { ... }
}
And in the tests I would like to inject a FakeDatabase object instead Database. I've been looking in Internet but the best that I found is:
Add a parameter to the constructor.
Convert the val database to a var so in the test I could access the attribute by the underlying and replace it.
Both solutions solve the problem but are very dirty.
Isn't a better way to solve the problem?
Thanks!
The two primary options for this scenario are:
Dependency Injection Use a DI framework to inject a real or mock service as needed. In Akka: http://letitcrash.com/post/55958814293/akka-dependency-injection
Cake Pattern This is a Scala-specific way of achieving something akin to dependency injection without actually relying on injection. See: Akka and cake pattern
Echoing the advice here, I wouldn't call injecting the database in the constructor dirty. It might have plenty of benefits, including decoupling actor behaviour from the particular database instance.
However if you know there is only ONE database you will be always using in your production code, then think about defining a package level accessible constructor and a companion object returning a Props object without parameters by default.
Example below:
object MyActor {
def props() : Props = Props(new MyActor(new Database()))
}
class MyActor private[package](database : IDatabase) extends Actor {
def receive = { ... }
}
In this case you will still be able to inject the test database in your tests case (given the same package structure), but prevent users of your code from instantiating MyActor with unexpected database instance.