2

このシナリオを整理するのに助けが必要です。依存関係を注入したいAkkaアクター、この場合はRemoteFetcherがあります。これも、テストでモックしたいと思います。そのようです:

main / src / scala / 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をコンパイルするには、暗黙のオブジェクトをインポートする必要があるということです。しかし、テストファイルでこれをシャドウ/オーバーライドするにはどうすればよいですか。暗黙の引数を使用しない理由は、すべてのアクターのコンストラクター引数を変更する必要がないようにするためです。

型クラスの依存性注入パターンを見回して読んでいると、チュートリアルに従って機能しますが、例のようにテストしてオーバーライドしたい場合は機能しません。

4

2 に答える 2

1

暗黙的にそれを行う方法はわかりませんが、通常は次のように代わりに注入できます。

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)。インポートでは、後で注入できるようにするのではなく、実装を定義しました。

于 2013-01-15T01:45:54.440 に答える
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

暗黙的なパラメーター解決の優先順位規則の詳細については、この投稿を参照してください。

于 2013-01-15T02:10:10.940 に答える