当前位置: 首页 > 知识库问答 >
问题:

自定义ApplicationLoader如何启动依赖项注入执行元并进行测试?

哈襦宗
2023-03-14

在“依赖注入Actors”中,展示了如何将参数注入子Actors的构造函数中。父执行元使用injectedChild只允许将未注入的参数传递给子执行元(在子执行元创建时),然后让Guice注入其馀的参数。为此,它扩展了InjectedActorSupport并将子工厂注入构造函数:

class MyParent @Inject() (childFactory: MyChild.Factory,
                           @Assisted something: Something,
                           @Assisted somethingElse: SomethingElse) extends Actor with InjectedActorSupport
[..]
    val child: ActorRef = injectedChild(childFactory(something, somethingElse), childName)

但是启动父级并且不是执行元而是自定义ApplicationLoader的类怎么办?如何从那里启动父级演员?文件中没有提到这一点。

class MyLoader @Inject() (parentFactory: MyParent.Factory) extends ApplicationLoader with Actor with InjectedActorSupport {
[..]
val parent = injectedChild(parentFactory(something, somethingElse), parentName)
class MyModule extends AbstractModule with AkkaGuiceSupport {
  def configure = {
    bindActor[MyParent](parentName)
    bindActor[MyLoader](loaderName)
    bindActorFactory[MyChild, MyChild.Factory]
    bindActorFactory[MyParent, MyParent.Factory]
  }
}

类MyLoaderSpec(_System:ActorSystem,隐式val ec:ExecutionContext)使用WordSpecLike扩展TestKit(_System),并使用Matchers{val loader=new SimstimLoader(???)

重写def beforeAll():Unit={Loader.Load(ApplicationLoader.CreateContext(new Environment(new File(“.”),ApplicationLoader.GetClass.GetClassLoader,Mode.Test)))}

提前一百万谢谢你!

共有1个答案

高自怡
2023-03-14

下面是我如何解决这个问题的。

-->如何启动需要依赖注入的父执行元。首先,如果您像我一样需要依赖注入一个不知道如何传递和从哪里传递的实例,那么手动启动这样的actor是不可能的。解决方案是让Guice自动启动执行元。这是怎么做的。首先,为Guice创建绑定模块:

class MyModule extends AbstractModule with AkkaGuiceSupport{

  override def configure(): Unit = {
    bindActor[Root](Root.NAME)
    bind(classOf[StartupActors]).asEagerSingleton()
  }
}

然后,通过在conf/application.conf中添加以下内容,告诉Play绑定器模块的位置:

play.modules={
  enabled += "my.path.to.MyModule"
}
class StartupActors @Inject() (@Named(Root.NAME) root: ActorRef) {
  play.api.Logger.info(s"Initialised $root")
}
object Root {
  final val NAME = "THERoot"
  case class ParseConfiguration()
}

class Root @Inject()(configuration: Configuration, projectDAO: ProjectDAO) extends Actor {
  val resultingVar: Something = myConfigParsing()

  override def preStart(): Unit = {
    context.actorOf(Props(new MyParent(resultingVar: Something, somethingElse: SomethingElse, projectDAO: ProjectDAO)))
  }

  override def receive: Receive = {
    case ParseConfiguration => sender ! myConfigParsing()
    case _ => logger.error("Root actor received an unsupported message")
  }
}
class MyParent(something: Something, somethingElse: SomethingElse, projectDAO: ProjectDAO) extends Actor { ... }
import akka.actor.{ActorRef, ActorSystem, Props}
import akka.testkit.{TestKit, TestProbe}
import com.typesafe.config.ConfigFactory
import org.mockito.Mockito.mock
import org.scalatest.{BeforeAndAfterAll, WordSpecLike}
import org.specs2.matcher.MustMatchers
import play.api.Configuration
import scala.concurrent.ExecutionContext

class RootSpec(_system: ActorSystem) extends TestKit(_system)
  with WordSpecLike with BeforeAndAfterAll with MustMatchers {

  implicit val ec: ExecutionContext = scala.concurrent.ExecutionContext.global
  val conf: com.typesafe.config.Config = ConfigFactory.load()
  val configuration: Configuration = Configuration(conf)
  val projectDAOMock: ProjectDAO = mock(classOf[ProjectDAO])

  private var mainActor: ActorRef = _
  private var something: Something = Something.empty

  def this() = this(ActorSystem("MySpec"))

  override def afterAll: Unit = {
    system.shutdown()
  }

  override def beforeAll(): Unit = {
    mainActor = system.actorOf(Props(new Root(configuration, projectDAOMock)), Root.NAME)
  }

  "RootSpec: Root Actor" should {
    val probe = TestProbe()

    "successfully parse the configuration file" in {
      probe.send(mainActor, ParseConfiguration)
      something = probe.expectMsgPF() {
        case msg => msg.asInstanceOf[Something]
      }
    }
  }
}

然后通过方便地提供mock对象来代替配置解析产生的var来测试MyParent:

import akka.actor.{ActorRef, ActorSystem, Props}
import akka.testkit.{TestKit, TestProbe}
import org.mockito.Mockito
import org.mockito.Mockito._
import org.scalatest.{BeforeAndAfterAll, WordSpecLike}
import org.specs2.matcher.MustMatchers
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.{ExecutionContext, Future}

case class AnyProjectAPI(val projectAPI: ProjectAPI) extends AnyVal
class MyParentSpec(_system: ActorSystem, implicit val ec: ExecutionContext) extends TestKit(_system)
  with WordSpecLike with BeforeAndAfterAll with MustMatchers {
  val something = mock(classOf[Something])
  val somethingElse = mock(classOf[somethingElse])
  val projectDAOMock: ProjectDAO = mock(classOf[ProjectDAO])

  val projectTest: ProjectAPI = new ProjectAPI(allMyRandomConstructorArguments),
  val projectsList: List[ProjectAPI] = List(projectTest)
  val expectedCreationId = 1
  private var parent: ActorRef = _

  def this() = this(ActorSystem("MySpec"), scala.concurrent.ExecutionContext.global)

  override def afterAll: Unit = {
    system.shutdown()
  }

  override def beforeAll(): Unit = {
    parent = system.actorOf(Props(new MyParent(something, somethingElse, projectDAOMock)), MyParent.NAME)
  }

  "MyParentTesting: parent's pull request" should {
    when(myProjApi.getAllProjects).thenReturn(Future {projectsList})
    val anyProject: AnyProjectAPI = AnyProjectAPI(org.mockito.Matchers.any[ProjectAPI])
    Mockito.when(projectDAOMock.create(org.mockito.Matchers.any[ProjectAPI]))
      .thenReturn(Future {expectedCreationId}: Future[Int])
    val probe = TestProbe()
    val probe1 = TestProbe()

    "be successfully satisfied by all children when multiple senders are waiting for an answer" in {
      probe.send(parent, UpdateProjects)
      probe1.send(parent, UpdateProjects)
      allChildren.foreach(child =>
        probe.expectMsg(expectedCreationId))
      allChildren.foreach(child =>
        probe1.expectMsg(expectedCreationId))
    }
  }
}
 类似资料:
  • 我正在寻找有关如何改进当前测试类(以下示例)的设计的建议,该类依赖于具有自定义配置的。我通常使用构造函数注入来注入一个在整个应用程序中一致的HttpClient,但是,因为这是在类库中,所以我不能依赖库的使用者来正确设置。 null 这个设置对我来说似乎相当复杂,我希望有人能提出一个改进,但我知道这可能是相当主观的,所以如果有任何既定的模式或设计规则要遵循在这种情况下,我会非常感谢听到他们。 我包

  • 例如,Foos的资源可能如下所示: 对于酒吧:

  • 我编写了以下来让Jackson将一个数组的整数序列化为JSON: 此处使用该类: 我想测试序列化程序的行为,并得出以下结论: 但是,不向写入任何内容。我做错了什么?

  • 我正在我的项目中使用模块,该模块公开了要监视的RESTendpointURL 默认情况下,仅公开 和 终结点。 根据我的使用案例,我正在通过< code > application . properties 文件自定义endpoint。 我想了解,Spring启动究竟在哪里为和创建实际的endpoint,以及它如何通过HTTP公开它们?

  • 我尝试在我的活动中注入修改,但我得到了空异常 这是AndroidApplication类

  • 问题内容: 我的团队正在研究依赖项注入框架,并试图在使用Google-Guice和PicoContainer之间做出选择。 我们正在寻找框架中的几件事情: 较小的代码占用空间-我的意思是较小的代码占用空间是我们不想在我们的代码库中到处都有依赖项注入代码垃圾。如果我们需要在将来进行重构,我们希望它尽可能简单。 性能-创建和注入对象时,每个框架有多少开销? 易于使用-学习曲线是否很大?我们是否必须编写