1

ServletUnit に便利な API を提供するために、Scala でServletUnitTestトレイトを作成しています。私は次のようなことを念頭に置いています。

/**
 * Utility trait for HttpUnit/ServletUnit tests
 * 
 * @param [T] Type parameter for the class under test
 */
trait ServletUnitTest[T <: HttpServlet] {
   /**
    * Resource name of the servlet, used to construct the servlet URL.
    */
   val servletName: String

   /**
    * Servlet class under test
    */
   implicit val servletClass: Manifest[T] 

   /**
    * ServletUnit {@link ServletRunner}
    */
   sealed lazy val servletRunner: ServletRunner = {
      val sr = new ServletRunner();
      sr.registerServlet(servletName, servletClass.erasure.getName);
      sr
   }

   /**
    * A {@link com.meterware.servletunit.ServletUnitClient}
    */
   sealed lazy val servletClient = servletRunner.newClient

   /**
    * The servlet URL, useful for constructing WebRequests
    */
   sealed lazy val servletUrl = "http://localhost/" + servletName

   def servlet(ic: InvocationContext) = ic.getServlet.asInstanceOf[T]
}

class MyServletTest extends ServletIUnitTest[MyServlet] {
   val servletName = "download"

   // ... test code ...
}

このコードは書かれたとおりにコンパイルされませんが、うまくいけば私の意図は明らかです。これを行う方法はありますか (マニフェストの有無にかかわらず)?

4

4 に答える 4

2

このトピックを調査しているときに、Jorge Ortiz によるこの scala-list の投稿で解決策を見つけました。これは私のためにトリックを行い、Aaron のものよりも簡単です。本質的に、彼の解決策は(言い換え):

  trait A[T] {
    implicit val t: Manifest[T]
  }

  class B[T: Manifest] extends A[T] {
    override val t = manifest[T]
  }

(私は2011年にこれを書いているので、2.7.7と互換性があるというOPリクエストを無視しています...)

于 2011-02-15T10:31:13.037 に答える
1

今のところ、Scala はインターフェイスとしてトレイトを表すので、この手法は機能します。ただし、トレイトを実装するこのアプローチにはいくつかの問題があります。メソッドがトレイトに追加されると、実装するクラスが必ずしも再コンパイルされるとは限りません。インターフェイス表現には、実際にメソッドを具体的に実装する別のクラスを指す転送メソッドしかないためです。これに対応して、今年初めに、実行時に JVM へのインターフェイス インジェクションを使用してこの問題を回避するという話がありました。パワーがこのアプローチを使用する場合、特性のタイプ情報はキャプチャする前に失われます。

于 2009-12-18T23:23:48.790 に答える
1

タイプ情報には、Java リフレクション API を使用してアクセスできます。きれいではありませんが、機能します:

trait A[T]{
  def typeParameter = {
    val genericType = getClass.getGenericInterfaces()(0).asInstanceOf[ParameterizedType]
    genericType.getActualTypeArguments()(0)
  }
}
class B extends A[Int]

new B().typeParameter -> java.lang.Integer

いくつかの不変チェックを追加する必要があります。私はハッピー パスのみを実装しました。

于 2009-12-22T08:47:35.337 に答える
0

うまくいく解決策を見つけましたが、トレイトの遅延値のいずれかが評価される前に、テストクラスがトレイトのメソッド(clazz)を呼び出す必要があるため、かなり厄介です。

/**
 * Utility trait for HttpUnit/ServletUnit tests
 * 
 * @param [T] Type parameter for the class under test
 */
trait ServletUnitTest[T <: HttpServlet] {
   /**
    * Resource name of the servlet, used to construct the servlet URL.
    */
   val servletName: String

   /**
    * Servlet class under test
    */
   val servletClass: Class[_] // = clazz
   protected def clazz(implicit m: Manifest[T]) = m.erasure

   /**
    * ServletUnit {@link ServletRunner}
    */
   sealed lazy val servletRunner: ServletRunner = {
      val sr = new ServletRunner();
      sr.registerServlet(servletName, servletClass.getName);
      sr
   }

   /**
    * A {@link com.meterware.servletunit.ServletUnitClient}
    */
   sealed lazy val servletClient = servletRunner.newClient

   /**
    * The servlet URL, useful for constructing WebRequests
    */
   sealed lazy val servletUrl = "http://localhost/" + servletName

   def servlet(ic: InvocationContext) = ic.getServlet.asInstanceOf[T]
}

class MyServletTest extends ServletIUnitTest[MyServlet] {
   val servletName = "download"
   val servletClass = clazz

   // ... test code ...
}
于 2009-12-23T20:47:10.400 に答える