3 利用 JUnit 3 和 4 进行单元测试
Groovy 简化了 JUnit 测试,使其更具有 Groovy 的特点。下面就来探讨一下 JUnit 3/4 与 Groovy 的集成情况。
3.1. JUnit 3
或者在 Groovy 类中,最显著支持 JUnit 3 测试的一个类是 GroovyTestCase
类。由于派生自 junit.framework.TestCase
,所以它提供了大量的额外方法,使 Groovy 测试变得易如反掌。
虽然 GroovyTestCase
继承自 TestCase
,但这并不意味在项目中无法使用 JUnit 4 的一些特性。实际上,最近发布的一些 Groovy 版本都带有打包的 JUnit 4,并且带有对 TestCase
的后向支持实现。在 Groovy 邮件列表中的一些对是否使用 GroovyTestCase
或 JUnit 4 的讨论中,人们认为这种选择更多是由个人口味来决定的,但利用 GroovyTestCase
,你能免费使用大量的方法,便于编写特定类型的测试。
下面就来看看 GroovyTestCase
所提供的一些方法,完整的方法列表位于 [groovy.util.GroovyTestCase] ( http://docs.groovy-lang.org/2.4.5/html/gapi/index.html?groovy/util/GroovyTestCase.html ) 的 JavaDoc 文档中。另外,不要忘记它继承自 junit.framework.TestCase
,后者继承了所有的 assert*
方法。
3.1.1 断言方法
GroovyTestCase
继承自 junit.framework.TestCase
,因此也间接继承了大量的断言方法,从而可以应用到每一个测试方法中:
class MyTestCase extends GroovyTestCase {
void testAssertions() {
assertTrue(1 == 1)
assertEquals("test", "test")
def x = "42"
assertNotNull "x must not be null", x
assertNull null
assertSame x, x
}
}
如上所示,与 Java 不同,可以在大多数场合忽略括号,从而可以使 JUnit 断言方法调用表达式实现更好的可读性。
assertScript
是一种由 GroovyTestCase
添加的有趣方法,它能保证指定的 Groovy 代码字符串成功执行,不会导致任何异常。
3.1.2 shouldFail
方法
shouldFail
用于查看指定代码块是否失败,如果失败,断言成立,否则断言失败。
void testInvalidIndexAccess1() {
def numbers = [1,2,3,4]
shouldFail {
numbers.get(4)
}
}
上例使用了基本的 shouldFail
方法接口,使用了一个 groovy.lang.Closure
做单一参数。 Closure
持有的代码被认为会在运行时中止。
如果我们要对特定 java.lang.Exception
类型进行 shouldFail
断言,我们可以使用一个 shouldFail
实现,其中第一个参数为 Exception
类,第二个参数为 Closure
类。
void testInvalidIndexAccess2() {
def numbers = [1,2,3,4]
shouldFail IndexOutOfBoundsException, {
numbers.get(4)
}
}
如果抛出 IndexOutOfBoundsException
(或其后代类),则测试用例失败。
shouldFail
其实还有一个隐藏的优点:返回异常消息。如果想对异常错误消息进行断言,这一点很有用。
void testInvalidIndexAccess3() {
def numbers = [1,2,3,4]
def msg = shouldFail IndexOutOfBoundsException, {
numbers.get(4)
}
assert msg.contains('Index: 4, Size: 4')
}
3.1.3 notYetImplemented
方法
notYetImplemented
方法受 HtmlUnit 影响很大。允许编写一个测试方法,但把它标记为还未实现。只要测试方法失败,并且被标记为 notYetImplemented
,测试就依然能够通过。
void testNotYetImplemented1() {
if (notYetImplemented()) return 1⃣️
assert 1 == 2 2⃣️
}
1⃣️ 要想使 GroovyTestCase
获取当前方法堆栈,就需要调用 notYetImplemented
。
2⃣️ 只要测试结果为 false
,测试执行就会成功。
可以用 @NotYetImplemented
注释来替代 notYetImplemented
方法。它能注释一个未实现方法,带有和 GroovyTestCase##notYetImplemented
相同的行为,只是不需要调用 notYetImplemented
方法。
@NotYetImplemented
void testNotYetImplemented2() {
assert 1 == 2
}
3.2 JUnit 4
利用 Groovy 编写 JUnit 4 测试用例没有任何限制。 groovy.test.GroovyAssert
可以保存各种静态方法,它们可以用于替代 JUnit 4 测试中的 GroovyTestCase
方法。
import org.junit.Test
import static groovy.test.GroovyAssert.shouldFail
class JUnit4ExampleTests {
@Test
void indexOutOfBoundsAccess() {
def numbers = [1,2,3,4]
shouldFail {
numbers.get(4)
}
}
}
如上所示, GroovyAssert
中的静态方法都在类定义之前导入进来,所以 shouldFail
可以像在 GroovyTestCase
中那样使用。
由于 groovy.test.GroovyAssert
来源自 org.junit.Assert
,所以它继承了 JUnit 所有的断言方法。但由于强力断言语句的引入,依赖断言语句成了一种良好实践,不再需要 JUnit 断言方法,而改善的消息也成为了这样做的一个主要因素。
GroovyAssert.shouldFail
并不绝对等于 GroovyTestCase.shouldFail
。 GroovyTestCase.shouldFail
返回异常消息, GroovyAssert.shouldFail
返回异常本身,获取异常消息还需要写一些代码,但反过来说也不是没有好处,你可以访问异常的其他属性和方法:
@Test
void shouldFailReturn() {
def e = shouldFail {
throw new RuntimeException('foo',
new RuntimeException('bar'))
}
assert e instanceof RuntimeException
assert e.message == 'foo'
assert e.cause.message == 'bar'
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论