我想帮助整理这个场景。我有一个Akka演员,我想注入一个依赖,在这种情况下RemoteFetcher,我也想在我的测试中模拟。像这样:
主/ SRC /阶/的 mypackage的/ Services.scala
package mypackage
import RemoteFetcherFileSystem._
trait RemoteFetcher {
def fetch( path:String ): Future[Stream[String]]
}
class MyRemoteResourceActor extends Actor with ActorLogging {
def fetchRemote( path:String ) = implicitly[RemoteFetcher].fetch( path )
def receive = {
case FetchRemoteResource( path ) => fetchRemote( path ).map( _.foreach( sender ! _ ) )
}
}
为此,我有一个隐含的对象,我导入上面的文件。看起来像这样:
implicit object RemoteFetcherFileSystem extends RemoteFetcher {
def fetchRemote( path:String ) = Future[Stream[String]] { ... reading from file system ... }
}
现在在我的测试中,我有来自akka-testkit的TestActor。在这里,我想改为导入我的模拟依赖:
implicit object RemoteFetcherMock extends RemoteFetcher {
def fetchRemote( path:String ) = Future[Stream[String]] { ... mock implementation ... }
}
我的问题是要编译Services.scala我需要导入隐式对象。但是我如何在我的测试文件中影响/覆盖它。我没有使用隐式参数的原因是我想避免修改我的所有actor构造函数参数。
当我环顾四周并阅读类型类依赖注入模式时,我按照教程开始工作,但是当我想在我的例子中进行测试和覆盖时,我不能让它工作。< / p>
答案 0 :(得分:1)
我不确定如何使用implicits,但通常可以像这样注入:
trait RemoteFetcherComponent {
def remoteFetcher: RemoteFetcher
trait RemoteFetcher {
def fetch(path: String): Future[Stream[String]]
}
}
trait RemoteFetcherFileSystemComponent extends RemoteFetcherComponent {
val remoteFetcher = RemoteFetcherFileSystem
object RemoteFetcherFileSystem extends RemoteFetcher {
def fetch(path: String): Future[Stream[String]] = ???
}
}
class MyRemoteResourceActor extends Actor with ActorLogging with RemoteFetcherFileSystemComponent {
def fetchRemote(path: String) = remoteFetcher.fetch(path)
def receive = {
case FetchRemoteResource(path) => fetchRemote(path).map( _.foreach(sender ! _))
}
}
val myRemoteResourceActor = new MyRemoteResourceActor()
然后测试值将如此定义:
trait RemoteFetcherMockComponent extends RemoteFetcherComponent {
def remoteFetcher = RemoteFetcherMock
object RemoteFetcherMock extends RemoteFetcher {
def fetch(path: String): Future[Stream[String]] = ???
}
}
val myMockedResourceActor = new MyRemoteResourceActor with RemoteFetcherMockComponent {
override val remoteFetcher = super[RemoteFetcherMockComponent].remoteFetcher
}
您遇到隐含问题的原因是因为您使用它的方式与仅使用def fetchRemote(path: String) = RemoteFetcherFileSystem.fetch(path)
没有区别。通过导入,您已经定义了实现,而不是允许稍后注入。
答案 1 :(得分:0)
您还可以将implicitly
更改为隐式参数:
trait RemoteFetcher {
def fetch(path: String): Future[Stream[String]]
}
object RemoteFetcher {
implicit val fetcher = RemoteFetcherFileSystem
}
class MyRemoteResourceActor extends Actor with ActorLogging {
def fetchRemote(path: String)(implicit remoteFetcher: RemoteFetcher) = remoteFetcher.fetch(path)
def receive = {
case FetchRemoteResource(path) => fetchRemote(path).map( _.foreach(sender ! _))
}
}
然后,您只需导入RemoteFetcher
即可覆盖在RemoteFetcherMock
的配套对象中解析的隐式。
有关隐式参数解析优先级规则的详细信息,请参阅this post。