Groovy之UT单元测试

ProjectDaedalus

共 14658字,需浏览 30分钟

 · 2022-06-27


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

abstract.png

UT语法

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

@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开头

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开头

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

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

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类用于进行单元测试

@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用于断言数组长度,示例代码如下所示

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用于断言数组长度、内容完全一致

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用于断言两个对象的地址是否相同
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方法的结果
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用于断言闭包执行失败, 且内部嵌套异常为指定类型异常
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
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的测试类,分别如下所示

class IntegerTest extends GroovyTestCase {
    void test1() {
        assertSame(1,1)
    }

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

    void test3() {
        assertNotNull( 996 )
    }
}
class StringTest extends GroovyTestCase {
    void test1() {
        def name = "Aaron"
        assertSame( name, name )
    }

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

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

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

// 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脚本如下所示

// 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著
浏览 31
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报