Using JUnit @Rule with ScalaTest (e.g. TemporaryFolder)

末鹿安然 提交于 2019-12-01 15:43:57

You could solve the problem by creating a member field of type TemporaryFolder and returning this field value by the @Rule function.

class MyTest extends JUnitSuite {

  val _temporaryFolder = new TemporaryFolder

  @Rule
  def temporaryFolder = _temporaryFolder

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

Here is what I came up based on ScalaTest's documentation on fixtures. Still, I would like to know if there is a better solution.

  1. Loan-fixture method

    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)
        }
      }
    }
    
    • Pros: allows applying the rule only to tests where it is needed
    • Cons: not very elegant usage; clumsy when multiple TestRules are required
  2. Using stackable mixins with withFixture(test: NoArgTest) override

    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)
      }
    }
    
    • Pros: very simple usage, conveniently allows mixing multiple rules in
    • Cons: requires having a mixin for every rule; rules need to be invoked even for tests that don't need them; rule cannot be used e.g. in BeforeAfterEach#beforeEach()
  3. Overriding 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)
      }
    }
    
    • Cons: allows only one TestRule, making in generic to work with any rule instead of just TestRule would require an extra effort

Which one do you like the best?

zella

This worked for me. Based on answer. So annotation will be applied to to the (synthetic) getter method

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

class MyTest extends JUnitSuite {

  @(Rule @getter)
  val tempFolder = new TemporaryFolder

}

Just make sure to use junit version >4.11.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!