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

Mif*_*eet 10 junit unit-testing scala scalatest

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

所以我的问题是:

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

这是我尝试过的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
  }
}
Run Code Online (Sandbox Code Playgroud)

Til*_*ann 12

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

class MyTest extends JUnitSuite {

  val _temporaryFolder = new TemporaryFolder

  @Rule
  def temporaryFolder = _temporaryFolder

  @Test
  def test: Unit = {
    assert(temporaryFolder.newFile() !== null)
  }
}
Run Code Online (Sandbox Code Playgroud)


Mif*_*eet 11

以下是我根据ScalaTest 关于灯具文档提出的内容.不过,我想知道是否有更好的解决方案.

  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)
        }
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)
    • 优点:允许将规则仅应用于需要测试的地方
    • 缺点:用法不是很优雅; 当需要多个TestRule时笨拙
  2. 使用带有withFixture(test: NoArgTest)覆盖的可堆叠mixins

    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)
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)
    • 优点:非常简单的使用,方便地允许混合多个规则
    • 缺点:要求每个规则都有一个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)
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)
    • 缺点:只允许一个TestRule,使得泛型可以使用任何规则而不仅仅是TestRule需要额外的努力

你最喜欢哪一个?


zel*_*lla 5

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

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

class MyTest extends JUnitSuite {

  @(Rule @getter)
  val tempFolder = new TemporaryFolder

}
Run Code Online (Sandbox Code Playgroud)

只需确保使用junit版本> 4.11。