Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/119.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 用Akka路由器测试喷雾API_Scala_Akka_Spray - Fatal编程技术网

Scala 用Akka路由器测试喷雾API

Scala 用Akka路由器测试喷雾API,scala,akka,spray,Scala,Akka,Spray,我正在开发一个Spray API,使用Akka路由器将传入的消息发送到一个参与者池中,以处理逻辑。现在我想为API编写一些测试,但我正在努力为代码找到正确的结构。目前,API如下所示: import akka.actor.{ActorRef, ActorSystem, Props, Actor} import akka.io.IO import akka.routing.SmallestMailboxPool import akka.util.Timeout import akka.patter

我正在开发一个Spray API,使用Akka路由器将传入的消息发送到一个参与者池中,以处理逻辑。现在我想为API编写一些测试,但我正在努力为代码找到正确的结构。目前,API如下所示:

import akka.actor.{ActorRef, ActorSystem, Props, Actor}
import akka.io.IO
import akka.routing.SmallestMailboxPool
import akka.util.Timeout
import akka.pattern.ask
import com.typesafe.config.ConfigFactory
import spray.json._
import spray.can.Http
import scala.concurrent.duration._
import spray.routing._
import spray.http._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.Success
import scala.util.Failure


object implicits{
  implicit val system = ActorSystem("ApiSystem")
  implicit val timeout = Timeout(5.seconds)
  implicit val conf = ConfigFactory.load()
  // Custom case class for parsing JSON parameter.
  case class Msg(key1:String, key2:String, key3:Int)

  object JsonProtocol extends DefaultJsonProtocol {
    implicit val msg = jsonFormat3(Msg)
  }
  case class PostMsg(msg:String)
  case object PostSuccess
  case class PostFailure(msg:String)
}

import implicits._

object MyApi extends App {
  override def main(Args: Array[String]):Unit = {

    // create and start our service actor
    val service = system.actorOf(Props(new MyApiActor(system)), "MyApi-service")


    IO(Http) ? Http.Bind(service, interface = conf.getString("http.host"), port = conf.getInt("http.port"))
  }
}

class MyApiActor(system: ActorSystem) extends Actor with MyApiService {
  // the HttpService trait defines only one abstract member, which
  // connects the services environment to the enclosing actor or test
  def actorRefFactory = context

  // this actor only runs our route, but you could add
  // other things here, like request stream processing
  // or timeout handling
  def receive = runRoute(myRoute)
}


// this trait defines our service behavior independently from the service actor
trait MyApiService extends HttpService {
  import implicits.JsonProtocol._

  var actorPool = system.actorOf(SmallestMailboxPool(conf.getInt("actor-number")).props(Props(new HandlingActor(conf))), "msgRouter")

  val myRoute =
    path("msg") {
      post {
        entity(as[String]) { obj =>
          try{
            // if this parsing succeeds, the posted msg satisfies the preconditions set.
            obj.parseJson.convertTo[Msg]
          } catch {
            case e: DeserializationException => {
              complete(HttpResponse(status=StatusCodes.BadRequest, entity="Invalid json provided."))
            }
            case e: Exception => {
              complete(HttpResponse(status=StatusCodes.InternalServerError, entity="Unknown internal server error."))
            }
          }
          onComplete(actorPool ? PostMsg(obj)) {
            case Success(value) => complete(HttpResponse(status = StatusCodes.OK, entity = "Pushed Msg"))
            case Failure(value) => complete(HttpResponse(status = StatusCodes.InternalServerError, entity = "Handling failed."))
          }
        }
      }
    }
}
我想测试的是API对各种HTTP消息(即正确调用、错误调用等)的响应。handling actor中的逻辑只是将消息推送到Kafka总线,因此我想“模拟”这种行为(即,如果推送成功,能够测试API响应,以及当推送失败时会发生什么)

目前我最头疼的是如何设置测试。目前,我正在使用与所示的main方法相同的命令设置API,但我需要指定不同的actorPool,因为我不希望实际推送任何消息。我应该如何最好地实现这些测试


我使用的是Scalatest、Akka和Spray测试套件。(如有必要,还可能加上mockito进行模拟)

我有一些建议可以让您的测试更容易:

不要在您的trait中创建演员库。而是在路由中使用
def
而不是
val
从ActorPool注入
ActorRef
。然后将actorPool
TestProbe()
注入测试将更容易。例如(我没有尝试/编译此代码):

然后测试可以如下所示:

class HttpListenerSpec extends WordSpecLike with Matchers with ScalatestRouteTest with MyApiService {

  "An HttpListener" should {
    "accept GET at /msg" in {
        val actorPool = TestProbe()

        (stuff for responding with TestProbe()...)

        Get("/msg") ~> myRoute(actorPool.ref) ~> check {
          status shouldBe OK
          val response = responseAs[String]
          assert(...)
        }
    }
  }
}
另外,作为最后的建议。有一些隐式转换集成了spray json和spray,因此您可以执行
实体(如[Msg])
。请查看以下内容:

import spray.httpx.marshalling._
import spray.httpx.unmarshalling._
import spray.httpx.SprayJsonSupport._
import MsgJsonProtocol._

Spray testkit允许您直接测试路线,而无需启动actor系统。看起来您无论如何都必须这样做,所以您可以使用Akka testkit来控制这些参与者,并拥有一个测试参与者系统。也许这里的一些例子有助于路线测试和特质组合:太棒了!谢谢D我缺少的步骤是将路线更改为
def
而不是
val
import spray.httpx.marshalling._
import spray.httpx.unmarshalling._
import spray.httpx.SprayJsonSupport._
import MsgJsonProtocol._