Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JUnit Theories and Scala

I'm looking for a way to test my Scala code with multiple inputs. Comming from Java/JUnit, I immediately thought of @RunWith(Theories.class). Where I'm stuck is the usage of @DataPoints and the absence of static members/methods in Scala. So is there a way to write the following code in 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)
  }

}

I'm neither fixed on JUnit nor Theories so if there is something Scala-specific for this use case, I'm happy to use that.

like image 636
seb Avatar asked Dec 07 '25 03:12

seb


1 Answers

To make this work, you have to do two things: use a method[see edit below], not a value, and secondly, define your @DataPoints in a companion object. The following should work:

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)
  }
}

When you define methods or fields in a companion object in Scala, you get a static forwarder in the class. Decompiling using JAD:

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

So this takes care of the static problem. However, when we use a val numbers = ..., the annotation isn't carried over to the field, but it is for methods. So using def works.

As the others have said, if you're developing from scratch, it may be worth starting in a Scala framework like scalatest. The tool integration with scalatest is improving (i.e maven, Eclipse, Intellij), but it's not the level of JUnit, so evaluate it for your project before you start.

EDIT: In fact, after this discussion on scala-user, you can use val, but you need to tell the scala compiler to apply the DataPoints annotation to the static forwarder:

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

The getter annotation says that the @DataPoints annotation should be applied to the accessor method for the numbers field, that is the numbers() method which is created by the compiler. See package target.

like image 156
Matthew Farwell Avatar answered Dec 08 '25 19:12

Matthew Farwell