Scala + JUnit 怎么使用 @Rule

JUnit 是个很著名的飞行模式测试框架,即使到了 Scala 中还是免不了要用 JUnit Style 的测试方式,基于 Spec 的方式并不处处行得通,比如想要在 Scala 中使用 JMockit 框架时。

JUnit 提供给我们有两个扩展点,RunnerRule, Runner 扩展点一般被各种框架劫持了,自己搞个 @RunWith(SomeRunner.class) 可能让你无法在测试中应用框架。于是剩下了 Rule 是个更自由的扩展点,这里不讲述怎么定制自己的 Rule,而是怎么用它,怎么在 Scala 中用它。之前的一篇 JUnit 4 如何正确测试异常 中使用了 ExpectedException 这个 Rule。

Rule 的要求是: Annotates fields that reference rules or methods that return a rule. A field must be public, not static, and a subtype of TestRule (preferred) or MethodRule. A method must be public, not static, and must return a subtype of TestRule (preferred) or MethodRule. 属性或方法必须是 public 非静态的,它们的类型或返回类型必须分别是 TestRuleMethedRule

这里尝试以 Java 的方式使用另一个 Rule,TestName, 可以得到当前测试方法的名称

运行上面的测试,得到错误

[error] Test RuleTest.initializationError failed: java.lang.Exception: The @Rule 'name' must be public.
[error]     at com.novocode.junit.JUnitRunner.run(JUnitRunner.java:87)
[error]     at sbt.RunnerWrapper$1.runRunner2(FrameworkWrapper.java:220)
[error]     at sbt.RunnerWrapper$1.execute(FrameworkWrapper.java:233)
[error]     at sbt.ForkMain$Run.runTest(ForkMain.java:239)
[error]     at sbt.ForkMain$Run.runTestSafe(ForkMain.java:211)
[error]     at sbt.ForkMain$Run.runTests(ForkMain.java:187)
[error]     at sbt.ForkMain$Run.run(ForkMain.java:251)
[error]     at sbt.ForkMain.main(ForkMain.java:97)
[info] RuleTest
[info] x initializationError

'name’ 必须是 public 的,但是 Scala 的属性可以为 private/protected, 就是不能为 public 的,而是根据 val/var 生成 setter/getter 方法,默认时

Scala 为 val name  生成 public TestName name() 方法,为 var name 生成 public TestName name() 和 public void name_$eq(TestName arg) 方法。

而 JUnit 需要一个 public 的 name 属性该怎么办呢,得曲线救援。Scala 的方法是 public 的,而且 Scala 是符合 统一访问原则 的,所以可以让 @Rule 标在方法上,写成

这时候 name 和 nameRef 都能得到当前测试方法名。上面必须要两行,一行定义 name,另一行 @Rule 指向前面声明的 name,我们却不能把这两行写成

这样的话断言会失败

[error] Test RuleTest.testTestName failed: expected:<testTestName> but was:<null>

由 name.getMethodName() 的是 null

补充一下:JUnit 有两种类型的 Rule, 分别是 分别是 TestRuleMethedRule, 分别应用属性和方法中,在 JUnit 4.11 中带了一些实现:

TestRule: ErrorCollector, ExpectedException, ExternalResource, RuleChain, TemporaryFolder, TestName, TestWatcher, Timeout, Verifier

MethodRule: TestWatchman

在使用 MethodRule 上,Java  与 Scala 应该没用区别,Scala 像是在使用 MethodRule 一样使用 TestRule, 因为 @Rule 标注到方法上去了。

参考:

  1. http://www.scottlogic.com/blog/2013/07/18/betamax-in-scala.html
  2. http://randomallsorts.blogspot.com/2012/11/junit-411-whats-new-rules.html
  3. http://blog.jiffle.net/post/41125006846/extending-junit-functionality-with-additional

本文链接 https://yanbin.blog/scala-junit-how-to-rule/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments