0%

Groovy之UT单元测试

这里介绍下Groovy中的Unit Test单元测试

abstract.png

UT语法

由于Groovy中已经内置了Junit。故非常适合进行UT单元测试。这里介绍几种常见的进行单元测试语法示例。首先,我们写一个普通的Java类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class HelloWorld {
private String name;

public String hello(String otherName) {
StringBuilder sb = new StringBuilder();
sb.append("I'm " + name + ", ");
sb.append( "Hi " + otherName + "~" );
return sb.toString();
}
}

然后通过Groovy编写UT单元测试。具体地:

第一种:直接继承GroovyTestCase, 且方法名需要以test开头

1
2
3
4
5
6
7
class HelloWorldTest1 extends GroovyTestCase{
void testHello() {
HelloWorld helloWorld = new HelloWorld("Aaron")
String result = helloWorld.hello("Tony")
assert result == "I'm Aaron, Hi Tony~"
}
}

第二种:直接继承TestCase, 且方法名需要以test开头

1
2
3
4
5
6
7
class HelloWorldTest2 extends TestCase {
void testHello() {
HelloWorld helloWorld = new HelloWorld("Aaron")
String result = helloWorld.hello("Tony")
assert result == "I'm Aaron, Hi Tony~"
}
}

第三种:直接使用@Test注解, 方法名可随意

1
2
3
4
5
6
7
8
class HelloWorldTest3 {
@Test
void helloTest() {
HelloWorld helloWorld = new HelloWorld("Aaron")
String result = helloWorld.hello("Tony")
assert result == "I'm Aaron, Hi Tony~"
}
}

Assertion 断言

Groovy中内置了若干断言用于进行单元测试。为了便于演示,这里提供一个Java类用于进行单元测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
public class Flower {
private String type;

@Override
public String toString() {
return "This is a " + type +" Flower";
}

public String inspect() {
return "[Info]: " + type;
}

public void calcException(int i) {
try{
if( i==1 ) {
throw new FileNotFoundException();
} else if( i==2 ) {
throw new NullPointerException();
}
} catch (Exception e) {
throw new RuntimeException( e );
}
}

}

assertLength

assertLength用于断言数组长度,示例代码如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class AssertionDemo extends GroovyTestCase{
/**
* assertLength: 断言数组长度
*/
void test1() {
int[] nums = [1,3,5,7]
assertLength(4, nums)

char[] alphabet = ["T", "C", "Z"]
assertLength(3, alphabet)

def array = [996, "Aaron"] as Object[]
assertLength(2, array)
}

}

assertArrayEquals

assertArrayEquals用于断言数组长度、内容完全一致

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class AssertionDemo extends GroovyTestCase{
/**
* assertArrayEquals: 断言数组长度、内容完全一致
*/
void test2() {
Object[] nums1 = [1,3]
Object[] nums2 = [1,3]
assertArrayEquals(nums1 ,nums2)

Flower[] flowers1 = [ new Flower("牡丹"), new Flower("茉莉") ]
Flower[] flowers2 = [ new Flower("牡丹"), new Flower("茉莉") ]
assertArrayEquals( flowers1, flowers2 )
}
}

assertEquals、assertNotSame、assertSame

  • assertEquals用于断言内容是否相等
  • assertNotSame用于断言两个对象的地址是否不同
  • assertSame用于断言两个对象的地址是否相同
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class AssertionDemo extends GroovyTestCase{
/**
* assertEquals: 断言内容是否相等
* assertNotSame: 断言两个对象的地址是否不同
* assertSame: 断言两个对象的地址是否相同
*/
void test3() {
// 校验result变量是否为期待值
String result = "Aaron" + "." + "Zhu"
String expected = "Aaron.Zhu"
assertEquals(expected, result)

// 校验浮点数num1、num2、num3是否为期待值
double num1 = 100.01
double num2 = 100.1
double num3 = 99.9
double expectedNum = 100
// 浮点数比较需要设置阈值
double delta = 0.1
assertEquals(expectedNum, num1, delta)
assertEquals(expectedNum, num2, delta)
assertEquals(expectedNum, num3, delta)

String errorMsg = "浮点数不相等"
// 支持设置断言失败的信息
assertEquals(errorMsg, expectedNum, num3, delta)

Flower flower = new Flower("牵牛花")
Flower expectedObj = new Flower("牵牛花")
// 断言两个对象的内容是否相等
assertEquals( expectedObj, flower )
// 断言两个对象的地址是否不同
assertNotSame( expectedObj, flower )
// 断言两个对象的地址是否相同
assertSame( flower, flower )
}

}

assertToString、assertInspect

  • assertToString用于断言对象调用toString方法的结果
  • assertInspect用于断言对象调用inspect方法的结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class AssertionDemo extends GroovyTestCase{
/**
* assertToString: 断言对象调用toString方法的结果
* assertInspect: 断言对象调用inspect方法的结果
*/
void test4() {
Flower flower = new Flower(type: "向阳花")

String expected = "This is a 向阳花 Flower"
assertToString(flower, expected)

expected = "[Info]: 向阳花"
assertInspect(flower, expected)
}
}

shouldFail、shouldFailWithCause

  • shouldFail用于断言闭包执行失败, 并抛出指定或任意类型的异常
  • shouldFailWithCause用于断言闭包执行失败, 且内部嵌套异常为指定类型异常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class AssertionDemo extends GroovyTestCase{
/**
* shouldFail: 断言闭包执行失败, 并抛出指定或任意类型的异常
* shouldFailWithCause: 断言闭包执行失败, 且内部嵌套异常为指定类型异常
*/
void test5() {
// 断言闭包执行失败, 并抛出指定类型的异常
def msg1 = shouldFail(NullPointerException) {
new HashMap(null)
}
def msg2 = shouldFail(IllegalArgumentException) {
new HashMap(-1)
}

// 断言闭包执行失败, 并抛出任意类型的异常
def msg3 = shouldFail {
new HashSet(-1)
}

// 断言闭包执行失败, 且getCause方法获取的内部嵌套的异常为指定类型异常
Flower flower = new Flower()
def msg4 = shouldFailWithCause(FileNotFoundException) {
flower.calcException(1)
}
def msg5 = shouldFailWithCause(NullPointerException) {
flower.calcException(2)
}
}
}

assertTrue、assertFalse、assertNull、assertNotNull

  • assertTrue用于断言表达式为真
  • assertFalse用于断言表达式为假
  • assertNull用于断言对象为null
  • assertNotNull用于断言对象不为null
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class AssertionDemo extends GroovyTestCase{
/**
* assertTrue: 断言表达式为真
* assertFalse: 断言表达式为假
* assertNull: 断言对象为null
* assertNotNull: 断言对象不为null
*/
void test6() {
assertTrue( 200>1 )
assertFalse( 1>200 )

Flower flower = null
assertNull( flower )
flower = new Flower()
assertNotNull( flower )
}
}

Test Suite 测试套件

对于多个测试类,我们还可以编写Groovy脚本实现将多个测试类组织到一个Test Suite测试套件当中。为了便于演示,我们先写两个Groovy的测试类,分别如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
class IntegerTest extends GroovyTestCase {
void test1() {
assertSame(1,1)
}

void test2() {
assertTrue( 200>1 )
}

void test3() {
assertNotNull( 996 )
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class StringTest extends GroovyTestCase {
void test1() {
def name = "Aaron"
assertSame( name, name )
}

void test2() {
assertTrue( "Aaron".length()>1 )
}

void test3() {
assertNotNull( "Aaron" )
}
}

现在我们看看如何将这两个测试类组织到一个测试套件当中,Groovy脚本如下所示

1
2
3
4
5
6
7
8
9
10
// Groovy 测试套件示例 1
def testSuite = new TestSuite()
def groovyTestSuite = new GroovyTestSuite()

// 向测试套件中分别添加各单元测试类
testSuite.addTestSuite( groovyTestSuite.compile("IntegerTest.groovy") )
testSuite.addTestSuite( groovyTestSuite.compile("StringTest.groovy") )

// 执行测试套件
TestRunner.run( testSuite )

对于测试类较多的局面,其还支持路径、文件名匹配的方式添加测试类到测试套件当中。Groovy脚本如下所示

1
2
3
4
5
6
7
8
9
10
// Groovy 测试套件示例 2

// 单元测试类的路径匹配表达式 .表示当前路径
String basedir = "."
// 单元测试类的文件名匹配表达式
String pattern = "*Test.groovy"
// 构建测试套件
def testSuite = AllTestSuite.suite(basedir, pattern)
// 执行测试套件
TestRunner.run( testSuite )

上述两个Groovy测试类、两个Groovy脚本的目录结构如下所示

figure 1.jpeg

参考文献

  1. Groovy In Action · 2nd Edition Dierk König、Guillaume Laforge著
请我喝杯咖啡捏~

欢迎关注我的微信公众号:青灯抽丝