在 Scala 中存根 SOAP 请求

Stubbing SOAP requests in Scala

我使用 scalaxb to generate models and client part of the SOAP interface. For testing I use Betamax, which can also be used in Scala. However, scalaxb uses Netty as a transport, which ignores proxy settings 由 Betamax 设置。你会如何应对这种情况?

scalaxb 使用蛋糕模式,因此服务由 3 个部分构建,如下所示 example:

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.concurrent.duration._

val service = (new stockquote.StockQuoteSoap12Bindings with
  scalaxb.SoapClientsAsync with
  scalaxb.DispatchHttpClientsAsync {}).service
val fresponse = service.getQuote(Some("GOOG"))
val response = Await.result(fresponse, 5 seconds)
println(response)

并测试:

import co.freeside.betamax.{TapeMode, Recorder}
import co.freeside.betamax.proxy.jetty.ProxyServer
import dispatch._
import org.scalatest.{Tag, FunSuite}
import scala.concurrent.duration._

import scala.concurrent.{Await, Future}

class StockquoteSpec extends FunSuite with Betamax {

  testWithBetamax("stockquote", Some(TapeMode.READ_WRITE))("stockquote") { 
    val fresponse = service.getQuote(Some("GOOG"))
    val response = Await.result(fresponse, 5 seconds)
    println(response)
  }
}

trait Betamax {

  protected def test(testName: String, testTags: Tag*)(testFun: => Unit)

  def testWithBetamax(tape: String, mode: Option[TapeMode] = None)(testName: String, testTags: Tag*)(testFun: => Unit) = {
    test(testName, testTags: _*) {
      val recorder = new Recorder
      val proxyServer = new ProxyServer(recorder)
      recorder.insertTape(tape)
      recorder.getTape.setMode(mode.getOrElse(recorder.getDefaultMode()))
      proxyServer.start()
      try {
        testFun
      } finally {
        recorder.ejectTape()
        proxyServer.stop()
      }
    }
  }
}

版本:

Netty 确实可以使用代理。尽管 Netty 不读取代理设置的系统属性,但可以使用 ProxyServerSelector 注入设置。它是在 AsyncHttpClientConfig:

build 方法中创建的
if (proxyServerSelector == null && useProxySelector) {
    proxyServerSelector = ProxyUtils.getJdkDefaultProxyServerSelector();
}

if (proxyServerSelector == null && useProxyProperties) {
    proxyServerSelector = ProxyUtils.createProxyServerSelector(System.getProperties());
}

if (proxyServerSelector == null) {
    proxyServerSelector = ProxyServerSelector.NO_PROXY_SELECTOR;
}

唯一的障碍是 scalaxb 使用 useProxyProperties=false 的默认配置。您可以使用创建服务时可以使用的自定义 MyDispatchHttpClientsAsync 覆盖它:

val service = (new stockquote.StockQuoteSoap12Bindings with
  scalaxb.SoapClientsAsync with
  MyDispatchHttpClientsAsync {}).service

以及MyDispatchHttpClientsAsync的源码(重点是调用setUseProxyProperties(true)):

import com.ning.http.client.providers.netty.NettyAsyncHttpProvider
import com.ning.http.client.{AsyncHttpClientConfig, AsyncHttpClient}
import scalaxb.HttpClientsAsync

/**
 * @author miso
 */
trait MyDispatchHttpClientsAsync extends HttpClientsAsync {
  lazy val httpClient = new DispatchHttpClient {}

  trait DispatchHttpClient extends HttpClient {
    import dispatch._, Defaults._

    // Keep it lazy. See https://github.com/eed3si9n/scalaxb/pull/279
    lazy val http = new Http(new AsyncHttpClient(new NettyAsyncHttpProvider(new AsyncHttpClientConfig.Builder().setUseProxyProperties(true).build())))
//    lazy val http = Http.configure(_.setUseProxyProperties(true)) // Maybe later. See https://github.com/eed3si9n/scalaxb/issues/312

    def request(in: String, address: java.net.URI, headers: Map[String, String]): concurrent.Future[String] = {
      val req = url(address.toString).setBodyEncoding("UTF-8") <:< headers << in
      http(req > as.String)
    }
  }
}