TestNG
TestNG is a testing framework inspired from JUnit and NUnit but introducing some new functionalities that make it more powerful and easier to use.
快速开始
maven 引入
<dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>6.14.3</version>
    <scope>test</scope>
</dependency>
代码
- StringUtil.java
基础字符串测试工具类
public class StringUtil {
    /**
     * 是否为空
     * @param s 字符串
     * @return 是否为空
     */
    public static boolean isEmpty(final String s) {
        return null == s
                || "".equals(s.trim());
    }
}
- TestNg.java
import org.testng.Assert;
import org.testng.annotations.Test;
public class TestNg {
    @Test
    public void simpleTest() {
        final String string = "";
        Assert.assertTrue(StringUtil.isEmpty(string));
    }
}
运行结果:
===============================================
Default Suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================
用法和 Junit4 区别不大
DataProvider
DataProvider 让数据驱动测试变得更加简单。
我们首先看一个简单的例子,然后再讲解。
简单例子
- TestNg.java
我们对测试类做简单调整:
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class TestNg {
    /**
     * 是否为空数据准备
     * ps: 只需要返回的是 object[][],数据的来源可以如下:
     * xml,excel,ymal,txt,database....
     * @return 数据
     */
    @DataProvider(name = "isEmpty")
    public Object[][] isEmptyDataProvider() {
        return new Object[][]{
                {"", true},
                {null, true},
                {"    ", true},
                {"1", false},
                {"   1", false}
        };
    }
    @Test(dataProvider = "isEmpty")
    public void isEmptyTest(final String string, boolean result) {
        System.out.println(string+", "+result);
        Assert.assertEquals(result, StringUtil.isEmpty(string));
    }
}
测试结果:
, true
null, true
    , true
1, false
   1, false
===============================================
Default Suite
Total tests run: 5, Failures: 0, Skips: 0
===============================================
简单说明
- 数据的声明
我们使用 @DataProvider 声明一个 Object[][] 的返回值,然后在测试方法中指定使用这个数据集。
测试方法的参数,和我们数据集合定义的一一对应。
如此,TestNG 就会依次将数据集合中的数据放到方法中依次执行验证。
可以减少因为数据入参,而需要不断添加新的测试方法的困境。
- Object[][]
对于这个数据的获取,也让其变得拥有更多的灵活性。我们的数据来源可以自行定义:
- 
    txt 
- 
    excel 
- 
    ymal 
- 
    数据库 
….
一些想法
TestNG 当初的意图是因为 Junit 在注解出现之后,停滞了一段时间,现在很多功能都逐渐被 Junit 反超回来。
- 数据驱动测试
不过数据驱动测试,是个非常棒的想法。
- testng 不对的地方
个人认为应该拓展 Junit,而不是取代,没必要吃力不讨好,全部覆盖。
我们因为在高楼之上,建筑高楼。而不应该推倒重来。
除非是全新的思想,完全有信心远超旧事物。
Spock 的优点
Spock 是针对 Grovvy 一款很棒的测试框架。
清晰的测试流程
模式
大部分的代码,都应该遵守一种 arrange-act-assert 模式
实际案例
- Junit 测试常见代码
@Test
public void chargeCreditCard() {
    CreditCardBilling billing = new CreditCardBilling();
    Client client = new Client();
    billing.charge(client,150);
    assertEquals("Revenue should be recorded",150,billing.getCurrentRevenue());
}
有注释版本:
@Test
public void chargeCreditCard() {
    //1. a billing service and a customer with a valid credit card
    CreditCardBilling billing = new CreditCardBilling();
    Client client = new Client();
    //2. client buys something with 150 dollars
    billing.charge(client,150);
    //3. we expect the transaction to be recorded
    assertEquals("Revenue should be recorded",150,billing.getCurrentRevenue());
}
直观地可以发现,拥有注释的会更便于理解。但是不是每个程序员都会测试代码写注释。
- Spock 版本
public void "charging a credit card - happy path"() {
    given: "a billing service and a customer with a valid credit card"
    CreditCardBilling billing = new CreditCardBilling();
    Client client = new Client();
    when: "client buys something with 150 dollars"
    billing.charge(client,150);
    then: "we expect the transaction to be recorded"
    billing.getCurrentRevenue() == 150
}
更加便于阅读
灵活的命名
上一个例子,业务你已经发现了。
Spock 中,方法的命名是:charging a credit card - happy path。
Junit 中,却局限于 Java 本身的语法限制,只能命名为 chargeCreditCard,甚至还有如下的命名:
chargeCreditCard01
chargeCreditCard02
chargeCreditCard03
...
- 个人建议
我觉得这也不是无法解决,@Test 注解中可以新增一个属性,比如 label/remark 等,用来说明测试的意图,
并且在生成测试报告时,显示此属性即可。
但是,目前的测试注解中应该没有。(Junit4/TestNG6)
利于阅读的测试报告
由于 Spock 的 given-when-then 的规范性,测试报告可以直接生成可阅读的,包含了测试的逻辑。
报告可以清晰看到:
METHOD: charging a credit card - happy path
-----------------------------------------------------------------
GIVEN:  a billing service and a customer with a valid credit card
WHEN:  client buys something with 150 dollars
THEN:  we expect the transaction to be recorded
对于开发者、测试者、管理者都有着积极的作用。
- Junit 中能实现吗?
好像不能。。。
内置支持所有 + 终极解决方案
我觉得这就像笨重的 VS 和 VSC 的区别。
个人更喜欢插件化的,可拓展的工具。
