3

私の部署の複数のグループが、Spray を使用して REST ベースの Web サービスを開発し始めましたが、すべて同様の問題に直面しており、これまでのところ、優れた解決策はありませんでした。

次のものがあったとします。

FooService extends Actor { ??? }

そして他の場所:

path("SomePath") {
  id =>
    get {
      requestContext =>
        // I apologize for the janky Props usage here, just an example
        val fooService = actorRefFactory.actorOf(Props(new FooService(requestContext))) 
        queryService ! SomeMessage(id)
    }
}

言い換えれば、すべてのエンドポイントには対応するアクターがあり、ルート内でそのタイプのアクターがリクエストコンテキストでスピンアップされ、メッセージが渡され、そのアクターが HttpResponse を処理して停止します。

私は常に十分に単純なルート ツリーを持っていたので、アクタ自体だけを単体テストし、ルート テストを統合テストで処理できるようにしましたが、ここでは却下されました。問題は、単体テストの場合、人々がFooServiceMockFooServiceに置き換えられるようにしたいということです

この状況を処理する標準的な方法はありますか?

4

1 に答える 1

3

最後の瞬間に実装をミックスインできるケーキパターンを使用します。

trait MyService extends HttpService with FooService {
  val route =
    path("SomePath") { id =>
        get { requestContext =>
            val fooService = actorRefFactory.actorOf(fooProps(requestContext)) 
            queryService ! SomeMessage(id)
        }
    }
}

trait FooService {
  def fooProps(requestContext: RequestContext): Props
}

trait TestFooService extends FooService {
  def fooProps(requestContext: RequestContext) =
    Props(new TestFooService(requestContext))
}

trait ProdFooService extends FooService {
  def fooProps(requestContext: RequestContext) =
    Props(new FooService(requestContext))
}

trait MyTestService extends MyService with TestFooService

trait MyProdService extends MyService with ProdFooService

テキストエディタで書いたので、コンパイルできるかどうかわかりません。

アクターなしでテストを行いたい場合は、次の 2 行を抽出できます。

val fooService = actorRefFactory.actorOf(fooProps(requestContext)) 
queryService ! SomeMessage(id)

何らかのメソッドに変換し、その背後にアクターを隠します。例えば:

def processRequest[T](msg: T): Unit = {
  // those 2 lines, maybe pass other args here too like context
}

このメソッドは同じケーキ パターンの方法でオーバーライドでき、テストではアクターをまったく使用しないようにすることもできます。

于 2015-03-18T06:46:22.603 に答える