您将如何测试Scala.js库以获得JVM和JS实现的等效性?

时间:2015-07-23 14:30:37

标签: javascript scalatest scala.js

我正在使用Scala.js,并编写了一个为JVM和JS实现的特性。我使用第三方JVM和JS库在双方实现它,应该在JVM和浏览器中提供功能相同的结果。但是,我需要编写一个测试来验证它!

如果我只是测试两个vanilla Scala实现,我就知道该怎么做了。我写了特征输入的生成器,并从中驱动每个函数,比较每个函数的结果。 (我可以假设函数结果是布尔,整数,长整数,字符串,相同的集合,或者可能是toString()' d。

有人在那里做这种测试吗?

如果一个实现是在Javascript中,我该如何做到这一点?幻影? (我可以将生成的JS文件传递给它,而不是简单的JS-as-strings吗?)还有其他什么?

1 个答案:

答案 0 :(得分:2)

您可以在宏中使用Scala的reflective toolbox来在编译时(在JVM上)执行测试代码。然后,您可以使用结果并生成用于比较值的代码。

所以我们想写一个宏,给出以下代码:

FuncTest.test { (1.0).toString }

可以生成这样的内容:

assert("1.0" == (1.0).toString)

这实际上听起来比现在更难。让我们从FuncTest的宏骨架开始:

import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context

object FuncTest {
  def test[T](x: => T): Unit = macro FuncTestImpl.impl[T]
}

class FuncTestImpl(val c: Context) {
  import c.universe._

  def impl[T : WeakTypeTag](x: Tree): Tree = ???
}

impl内部,我们想在x中运行代码,然后生成一个断言(或者适合您使用的测试框架):

import scala.reflect.runtime.{universe => ru}
import scala.tools.reflect.ToolBox

def impl[T : WeakTypeTag](x: Tree): Tree = {
  // Make a tool box (runtime compiler and evaluater)
  val mirror = ru.runtimeMirror(getClass.getClassLoader)
  val toolBox = mirror.mkToolBox()

  // Import trees from compile time to runtime universe
  val importer = ru.mkImporter(c.universe)
  val tree = toolBox.untypecheck(importer.importTree(x))

  // Evaluate expression and make a literal tree
  val result = toolBox.eval(tree)
  val resultTree = reifyLiteral(result)

  // Emit assertion
  q"assert($x == $resultTree)"
}

我们遇到的唯一问题是reifyLiteral。它基本上应该采用任意值并从中创建一个文字。一般来说这很难/不可能。但是,对于某些基本值(基元,字符串等)来说非常容易:

/** Creates a literal tree out of a value (if possible) */
private def reifyLiteral(x: Any): Tree = x match {
  case x: Int => q"$x"
  case x: String => q"$x"

  // Example for Seq
  case x: Seq[_] =>
    val elems = x.map(reifyLiteral)
    q"Seq(..$elems)"

  case _ =>
    c.abort(c.enclosingPosition, s"Cannot reify $x of type ${x.getClass}")
}

就是这样。你现在可以写:

FuncTest.test { /* your code */ }

自动生成计算库的测试。

警告此工具箱目前没有注入正确的类路径。因此,如果您使用外部库(我假设您这样做),您也需要调整它。如果您需要帮助,请告诉我。