将模拟演员注入Spray路线进行测试

时间:2015-03-18 00:32:00

标签: scala unit-testing akka spray spray-test

我所在部门的多个小组已经开始使用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)
    }
}

换句话说,每个端点都有一个相应的actor,并且在路径内部,该类型的actor将与请求上下文一起旋转,一条消息将被传递给它,该actor将处理HttpResponse& ;停止。

我总是拥有足够简单的路由树,我只对Actors本身进行了单元测试,并让路由测试由集成测试处理,但我在这里已经被推翻了。所以问题是,对于单元测试,人们希望能够用 MockFooService 替换 FooService

是否有处理这种情况的标准方法?

1 个答案:

答案 0 :(得分: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

我是在文本编辑器中写的,所以我不确定它是否会编译。

如果你想在没有演员的情况下进行测试,你可以提取这两行:

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
}

这种方法可以用相同的蛋糕模式覆盖,对于测试你甚至可以避免使用演员。