JUnit Theories和Scala

时间:2011-12-20 08:31:38

标签: scala testing junit

我正在寻找一种使用多个输入来测试我的Scala代码的方法。来自Java / JUnit,我立刻想到了@RunWith(Theories.class)。 我遇到的问题是@DataPoints的使用以及Scala中缺少静态成员/方法。那么有没有办法在Scala中编写以下代码?

@RunWith(classOf[Theories])
class ScalaTheory {

  @DataPoints
  val numbers = Array(1, 2, 3)

  @Theory
  def shouldMultiplyByTwo(number : Int) = {
    // Given
    val testObject = ObjectUnderTest

    // When
    val result = testObject.run(number)

    // Then
    assertTrue(result == number * 2)
  }

}

我既不是JUnit也不是Theories,所以如果这个用例有特定于Scala的东西,我很乐意使用它。

3 个答案:

答案 0 :(得分:4)

要完成这项工作,您必须做两件事:使用方法[请参阅下面的编辑],而不是值,其次,在随播对象中定义@DataPoints。以下应该有效:

object ScalaTheory {
  @DataPoints
  def numbers() = Array(1, 2, 3) // note def not val
}

@RunWith(classOf[Theories])
class ScalaTheory {
  @Theory
  def shouldMultiplyByTwo(number : Int) = {
    // Given
    val testObject = ObjectUnderTest

    // When
    val result = testObject.run(number)

    // Then
    assertTrue(result == number * 2)
  }
}

在Scala中的伴随对象中定义方法或字段时,您将在类中获得静态转发器。使用JAD进行反编译:

@Theories
public static final int[] numbers()
{
    return ScalaTheory$.MODULE$.numbers();
}

因此,这将解决静态问题。但是,当我们使用val numbers = ...时,注释不会转移到字段,而是用于方法。因此,使用def可以正常工作。

正如其他人所说的那样,如果你是从头开始,那么可能值得开始使用像scalatest这样的Scala框架。与scalatest的工具集成正在改进(即maven,Eclipse,Intellij),但它不是JUnit的级别,因此在开始之前为您的项目评估它。

编辑:事实上,在this discussion on scala-user之后,您可以使用val,但是您需要告诉scala编译器将DataPoints批注应用于静态转发器:

object ScalaTheory {
  @(DataPoints @scala.annotation.target.getter)
  val numbers = Array(1, 2, 3)
}

getter注释表示@DataPoints注释应该应用于数字字段的访问器方法,即编译器创建的numbers()方法。请参阅package target

答案 1 :(得分:2)

我希望每个Scala测试框架都能满足您的需求。我只熟悉Specs2,所以这是我的镜头:

class DataPoints extends Specification {
  val objectUnderTest: Int => Int = _ + 2

  val testCases = 1 :: 2 :: 3 :: 4 :: Nil

  def is: Fragments = 
    (objectUnderTest must multiplyByTwo((_: Int))).foreach(testCases)    

  def multiplyByTwo(i: Int): Matcher[(Int) => Int] = 
    (=== (i * 2)) ^^ 
      ((f: Int => Int) => f(i) aka "result of applying %s to %d".format(f, i))
}

输出是:

result of applying <function1> to 1 '3' is not equal to '2'; result of applying <function1> to 3 '5' is not equal to '6'; result of applying <function1> to 4 '6' is not equal to '8'

声明

我并未声明这是非常易读的。我也不是Specs2的专家用户。

答案 2 :(得分:2)

就像ziggystar一样,我无法真正帮助你解决直接问题。但我强烈建议切换到scala测试框架。我个人最喜欢的是scalatest。

在这里的最后一个例子中:http://blog.schauderhaft.de/2011/01/16/more-on-testing-with-scalatest/我演示了编写运行多个输入的测试是多么简单和直接。这只是一个简单的循环!