将JUnit @Rule与ScalaTest一起使用(例如TemporaryFolder)

时间:2015-08-22 20:39:50

标签: scala unit-testing junit scalatest

我希望能够使用JUnit规则,例如我们已经在内部开发的TemporaryFolder或其他TestRule。   实现这一目标的最佳方法是什么?我知道JUnitSuite,但它似乎没有拿起@Rule注释。 无论如何,我想使用不同的ScalaTest套件。

所以我的问题是:

  • ScalaTest套装是否支持JUnit规则?
  • 如果没有,是否有可以使用Junit TestRule的库?
  • 如果没有,如何在Scala测试中使用JUnit TestRule
  • 或者是否有更合适的Scala特定方法来完成TemporaryFolder,或者例如Stefan Birkner System Rules提供的内容?

这是我尝试使用JUnitSuite

的内容
class MyTest extends JUnitSuite {
  //@Rule
  //val temporaryFolder = new TemporaryFolder() // throws java.lang.Exception: The @Rule 'temporaryFolder' must be public.

  @Rule
  def temporaryFolder = new TemporaryFolder()

  @Test
  def test: Unit = {
    assert(temporaryFolder.newFile() !== null) // java.lang.IllegalStateException: the temporary folder has not yet been created
  }
}

3 个答案:

答案 0 :(得分:12)

您可以通过创建TemporaryFolder类型的成员字段并通过@Rule函数返回此字段值来解决此问题。

class MyTest extends JUnitSuite {

  val _temporaryFolder = new TemporaryFolder

  @Rule
  def temporaryFolder = _temporaryFolder

  @Test
  def test: Unit = {
    assert(temporaryFolder.newFile() !== null)
  }
}

答案 1 :(得分:11)

以下是我根据ScalaTest documentation on fixtures提出的内容。不过,我想知道是否有更好的解决方案。

  1. 贷款夹具方法

    class LoanFixtureTest extends FunSuite {
      def withRule[T <: TestRule](rule: T)(testCode: T => Any): Unit = {
        rule(
          new Statement() {
            override def evaluate(): Unit = testCode(rule)
          },
          Description.createSuiteDescription("JUnit rule wrapper")
        ).evaluate()
      }
    
      test("my test") {
        withRule(new TemporaryFolder()) { temporaryFolder =>
          assert(temporaryFolder.newFile() !== null)
        }
      }
    }
    
    • 优点:允许仅将规则应用于需要的测试
    • 缺点:用法不是很优雅;当需要多个TestRule时笨拙
  2. 将可堆叠的mixins与withFixture(test: NoArgTest)覆盖

    一起使用
    trait TemporaryFolderFixture1 extends SuiteMixin {
      this: Suite =>
      val temporaryFolder = new TemporaryFolder
    
      abstract override def withFixture(test: NoArgTest) = {
        var outcome: Outcome = null
        val statementBody = () => outcome = super.withFixture(test)
        temporaryFolder(
          new Statement() {
            override def evaluate(): Unit = statementBody()
          },
          Description.createSuiteDescription("JUnit rule wrapper")
        ).evaluate()
        outcome
      }
    }
    
    class StackableTraitFixtureTest extends FunSuite with TemporaryFolderFixture1 {
      test("my test") {
        assert(temporaryFolder.newFile() !== null)
      }
    }
    
    • 优点:使用非常简单,方便地允许混合多个规则
    • 缺点:要求每个规则都有一个mixin;甚至对于不需要它们的测试也需要调用规则;规则不能用于,例如在BeforeAfterEach#beforeEach()
  3. 覆盖withFixture(test: OneArgTest)

    trait TemporaryFolderFixture2 {
      thisFixture: org.scalatest.fixture.FunSuite =>
      type FixtureParam = TemporaryFolder
    
      override protected def withFixture(test: OneArgTest): Outcome = {
        val temporaryFolder = new TemporaryFolder()
        var outcome: Outcome = null
        temporaryFolder(
          new Statement() {
            override def evaluate(): Unit = {
              outcome = withFixture(test.toNoArgTest(temporaryFolder))
            }
          },
          Description.createSuiteDescription("JUnit rule wrapper")
        ).evaluate()
        outcome
      }
    }
    
    class OneArgWithFixtureTest extends org.scalatest.fixture.FunSuite with TemporaryFolderFixture2 {
      test("my test") { temporaryFolder =>
        assert(temporaryFolder.newFile() !== null)
      }
    }
    
    • 缺点:只允许一个TestRule,使得泛型可以使用任何规则而不仅仅是TestRule需要额外的努力
  4. 你最喜欢哪一个?

答案 2 :(得分:3)

这对我有用。基于answer。因此注释将应用于 到(合成)getter方法

import org.junit._
import scala.annotation.meta.getter

class MyTest extends JUnitSuite {

  @(Rule @getter)
  val tempFolder = new TemporaryFolder

}

请务必使用junit版本&gt; 4.11。