【问题标题】:Using JUnit @Rule with ScalaTest (e.g. TemporaryFolder)将 JUnit @Rule 与 ScalaTest 一起使用(例如 TemporaryFolder)
【发布时间】:2015-11-16 14:13:28
【问题描述】:

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

所以我的问题是:

  • ScalaTest 套件是否支持 JUnit 规则?
  • 如果没有,是否有一个库可以让使用 Junit TestRules 成为可能?
  • 如果没有,如何在 Scala 测试中使用 JUnit TestRules?
  • 或者是否有更合适的特定于 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
  }
}

【问题讨论】:

    标签: scala unit-testing junit scalatest


    【解决方案1】:

    这是我根据 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)
          }
        }
      }
      
      • 优点:允许仅将规则应用于需要的测试
      • 缺点:不是很优雅的用法;当需要多个 TestRules 时很笨拙
    2. 使用带有withFixture(test: NoArgTest)覆盖的可堆叠mixin

      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 需要额外的努力

    你最喜欢哪一个?

    【讨论】:

      【解决方案2】:

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

      class MyTest extends JUnitSuite {
      
        val _temporaryFolder = new TemporaryFolder
      
        @Rule
        def temporaryFolder = _temporaryFolder
      
        @Test
        def test: Unit = {
          assert(temporaryFolder.newFile() !== null)
        }
      }
      

      【讨论】:

      • 啊,谢谢,这行得通:)。错过了多个 TemporaryFolder 实例的创建。最后,我们采用了可堆叠的 mixins 解决方案,这样我们就不会被 JUnitSuite 锁定。但无论如何,很高兴知道 @Rule 可以在 scalatest 中得到支持。
      • 很高兴我能帮上忙 :-)
      【解决方案3】:

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

      import org.junit._
      import scala.annotation.meta.getter
      
      class MyTest extends JUnitSuite {
      
        @(Rule @getter)
        val tempFolder = new TemporaryFolder
      
      }
      

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

      【讨论】:

        猜你喜欢
        • 2020-03-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-28
        • 1970-01-01
        • 1970-01-01
        • 2021-03-08
        相关资源
        最近更新 更多