在 ScalaTest 中使用 JUnit @Rule(例如 TemporaryFolder)
Using JUnit @Rule with ScalaTest (e.g. TemporaryFolder)
我希望能够使用 JUnit 规则,例如 TemporaryFolder
或我们已经在内部开发的其他 TestRule
。
实现该目标的最佳方法是什么?我知道 JUnitSuite,但它似乎没有接受 @Rule
注释。
无论如何,我想使用不同的 ScalaTest 套件。
所以我的问题是:
- ScalaTest 套件是否支持 JUnit 规则?
- 如果没有,是否有可以使用 Junit
TestRule
的库?
- 如果没有,如何在 Scala 测试中使用 JUnit
TestRule
s?
- 或者是否有更合适的特定于 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
}
}
这是我基于 ScalaTest 的 documentation on fixtures 得出的结论。不过还是想知道有没有更好的解决办法
贷款夹具法
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 时很笨拙
使用具有 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()
覆盖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 需要额外的努力
你最喜欢哪一个?
您可以通过创建类型为 TemporaryFolder
的成员字段并通过 @Rule
函数返回该字段值来解决问题。
class MyTest extends JUnitSuite {
val _temporaryFolder = new TemporaryFolder
@Rule
def temporaryFolder = _temporaryFolder
@Test
def test: Unit = {
assert(temporaryFolder.newFile() !== null)
}
}
这对我有用。基于 answer。所以注释将应用于
到(合成)getter 方法
import org.junit._
import scala.annotation.meta.getter
class MyTest extends JUnitSuite {
@(Rule @getter)
val tempFolder = new TemporaryFolder
}
只要确保使用 junit 版本 >4.11。
我希望能够使用 JUnit 规则,例如 TemporaryFolder
或我们已经在内部开发的其他 TestRule
。
实现该目标的最佳方法是什么?我知道 JUnitSuite,但它似乎没有接受 @Rule
注释。
无论如何,我想使用不同的 ScalaTest 套件。
所以我的问题是:
- ScalaTest 套件是否支持 JUnit 规则?
- 如果没有,是否有可以使用 Junit
TestRule
的库? - 如果没有,如何在 Scala 测试中使用 JUnit
TestRule
s? - 或者是否有更合适的特定于 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
}
}
这是我基于 ScalaTest 的 documentation on fixtures 得出的结论。不过还是想知道有没有更好的解决办法
贷款夹具法
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 时很笨拙
使用具有
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()
覆盖
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 需要额外的努力
你最喜欢哪一个?
您可以通过创建类型为 TemporaryFolder
的成员字段并通过 @Rule
函数返回该字段值来解决问题。
class MyTest extends JUnitSuite {
val _temporaryFolder = new TemporaryFolder
@Rule
def temporaryFolder = _temporaryFolder
@Test
def test: Unit = {
assert(temporaryFolder.newFile() !== null)
}
}
这对我有用。基于 answer。所以注释将应用于 到(合成)getter 方法
import org.junit._
import scala.annotation.meta.getter
class MyTest extends JUnitSuite {
@(Rule @getter)
val tempFolder = new TemporaryFolder
}
只要确保使用 junit 版本 >4.11。