• 走进Java接口测试之测试框架TestNG数据驱动(入门篇)


     https://mp.weixin.qq.com/s?__biz=MzIwNDY3MDg1OA==&mid=2247485789&idx=1&sn=fb6c0abd38419747e61d9b14dee10466&chksm=973ddbb8a04a52aeee5869d47b1d0ea01467f2c3bdb988ebd445d783dd080e0049754c78b60d&scene=178&cur_album_id=1517682088030879750#rd

    前言

    我们在前面的文章中,和大家分享过接口自动化测试一些基本的实现方法,但是,你很快就会发现,如果在测试脚本中硬编码测试数据的话,测试脚本灵活性会非常低。而且,对于那些具有重复的请求,而只是测试入参不同的用例来说,就会存在大量重复的代码。那么怎么把自己从简单、重复的工作中解放出来呢?这个时候我们应考虑把测试数据和测试脚本分离,也就是说数据驱动

    数据驱动的优势?

    • 数据驱动很好地解决了大量重复脚本的问题,实现了“测试脚本和数据的解耦”。目前几乎所有主流的自动化测试工具和框架都支持。

    • 数据驱动测试的数据不仅可以包括测试输入数据,还可以包含测试验证结果数据,甚至可以包含测试逻辑分支的控制变量。

    • 数据驱动的测试思想不仅适用于接口测试,也适合与单元测试,UI自动化测试,性能测试等

    常见提供数据的方式?

    • 硬编码

    • txt文件

    • Json

    • Yaml

    • 配置文件properties

    • execl

    • db

    • 网络中

    数据驱动的原理?

    测试脚本中通过 data provider 去数据源中读取一行数据,赋值给相应的变量,执行用例。接着再去文件中读取下一行数据,读取完所有的数据后,测试结束。参数化文件中有几行数据,测试用例就会被执行几次。如图所示:图片

    TestNG如何实现?

    我们可以在每个测试方法上使用任意数量的参数,并指示 TestNG 使用 @Parameters 注释传递正确的参数。

    TestNG有两种方法可以设置这些参数(@Factory 数据工厂不在此介绍):

    • 使用 testng.xml 图片

    • DataProvider 图片

    图片 注意:

    • TestNG.xml 中的参数可以是套件或测试级别;

    • DataProvider 中的参数可以将 Method 和 ITestContext 作为参数。

    testng.xml 中的参数

    如果简单参数,则可以在 testng.xml 中指定它们,在以下代码中,我们指定的参数 name 和 age 值。此 XML 参数在 testng.xml 中 定义:

    1. <suite name="parameter">

    2. <test name="param">

    3. <parameter name="name" value="zhangsan"/>

    4. <parameter name="age" value="10"/>

    5. <classes>

    6. <class name="com.zuozewei.springboottestngdatadrivendemo.paramter.ParamterTest"/>

    7. </classes>

    8. </test>

    9. </suite>

    测试方法将分别接收参数 name 和 age 的值。

    1. @Slf4j

    2. public class ParamterTest {

    3. @Test

    4. @Parameters({"name","age"})

    5. public void paramTest(String name,int age){

    6. log.info("name = [{}] ; age = [{}]" ,name,age);

    7. }

    8. }

    注意 @Parameters 可以被放置在下列位置:

    • 在任何已经有 @Test,@Before/After 或 @Factory 注释的方法上;

    • 最多只有一个测试类的构造函数。在这种情况下,TestNG 将调用此特定构造函数,并在需要实例化测试类时将参数初始化为 testng.xml 中指定的值。此功能可用于将类中的字段初始化为测试方法随后将使用的值。

    1. @Parameters({ "name", "age" })

    2. @BeforeMethod

    3. public void beforeTest(String name, String age) {

    4. m_name = name; // 查询数据源值

    5. m_age = age;

    6. }

    注意:

    • XML 参数按照与注释中相同的顺序映射到 Java 参数,如果数字不匹配,TestNG 将报错;

    • 参数是存在作用域的。在 testng.xml 中,可以在 suite 标记下或 test 下声明它们 。如果两个参数具有相同的名称,则它是 test 中定义的具有优先权。如果需要指定适用于所有测试的参数并仅为某些测试覆盖其值,这将非常方便。

    使用 DataProviders 的参数

    如果需要传递复杂参数或需要从 Java 创建的参数(复杂对象,从文件或数据库读取的对象等等),则在 testng.xml 中指定参数可能不够。在这种情况下,可以使用数据提供程序提供测试所需的值。数据提供程序是类上的一个方法,它返回一组对象数组。此方法使用 @DataProvider 注释。

    简单使用

    @DataProvider函数,需要定义属性 name:

    1. @DataProvider(name="data")

    2. public Object[][] providerData(){

    3. Object[][] objects = new Object[][]{

    4. {"zhangsan",10},

    5. {"lisi",20},

    6. {"wangwu",30}

    7. };

    8. return objects;

    9. }

    @Test 测试用例,属性 dataProvider 需要指定对应的数据提供者名称。

    1. @Test(dataProvider = "data")

    2. public void testDataProvider(String name,int age){

    3. log.info("name = [{}] ; age = [{}]" ,name,age);

    4. }

    执行结果:

    1. name = [zhangsan] ; age = [10]

    2. name = [lisi] ; age = [20]

    3. name = [wangwu] ; age = [30]

    4. ===============================================

    5. Default Suite

    6. Total tests run: 3, Failures: 0, Skips: 0

    7. ===============================================

    @DataProvider函数插入参数使用

    @DataProvider 函数可以插入 Method 和 ITestContext 类型参数,这两个参数里面可以获取很多有用的信息。

    @DataProvider函数:

    1. @DataProvider(name="methodData")

    2. public Object[][] methodDataTest(Method method){

    3. Object[][] result=null;

    4. if(method.getName().equals("test1")){

    5. result = new Object[][]{

    6. {"zhangsan",20},

    7. {"lisi",25}

    8. };

    9. }else if(method.getName().equals("test2")){

    10. result = new Object[][]{

    11. {"wangwu",50},

    12. {"zhaoliu",60}

    13. };

    14. }

    15. return result;

    16. }

    @Test 测试执行脚本:

    1. @Test(dataProvider = "methodData")

    2. public void test1(String name,int age){

    3. log.info("test111方法: name = [{}] ; age = [{}]" ,name,age);

    4. }

    5. @Test(dataProvider = "methodData")

    6. public void test2(String name,int age){

    7. log.info("test222方法: name = [{}] ; age = [{}]" ,name,age);

    8. }

    执行结果:

    1. test111方法: name = [zhangsan] ; age = [20]

    2. test111方法: name = [lisi] ; age = [25]

    3. test222方法: name = [wangwu] ; age = [50]

    4. test222方法: name = [zhaoliu] ; age = [60]

    5. ===============================================

    6. Default Suite

    7. Total tests run: 7, Failures: 0, Skips: 0

    8. ===============================================

    延迟数据提供者

    有的场景我们需要大量参数进行读取,比如参数数据源是 DB,而数据达到百万级,这样测试程序遍历所有数据时,可能就会导致内存溢出,

    那么我们怎样解决这个问题?当我们获取了一条数据,对它执行测试方法,然后就废弃这个数据对象,再测试下一个书。这个原则是延迟初始化,这个思想就是当你真正需要一个对象时才创建它,而不是提前创建它。

    为了实现这种方法,TestNG 允许我们从数据提供者返回一个 Iterator 对象,而不是一个二维对象数组。

    Iterator 是 java.util 包中的一个接口,它的方法签名如下:

    1. public interface Iterator<E> {

    2. boolean hasNext();

    3. E next();

    4. default void remove();

    5. }

    它可以通过 next 调用下一组数据,这样就有机会在最后一刻实例化相应的对象,即刚好在需要在这些参数的测试方法被调用之前。

    下面例子是重写后的例子,我们实现了一个 Iterator,它将返回 4 个带有不同ID的对象:

    1. public class AccoutIterator implements Iterator {

    2. private int index =0;

    3. static private final int MAX =4;

    4. @Override

    5. public boolean hasNext() {

    6. return index < MAX;

    7. }

    8. @Override

    9. public Object next() {

    10. return new Object[]{

    11. //这里就是放入要实现的对象或者一组数据

    12. "延迟数据提供:"+ (index++)

    13. };

    14. }

    15. @Override

    16. public void remove() {

    17. throw new UnsupportedOperationException("remove");

    18. }

    @DataProvider函数调用:

    1. @DataProvider(name = "iterator")

    2. public Iterator<Object[]> iteratorDataProvider(){

    3. return new AccoutIterator();

    4. }

    @Test测试运行函数:

    1. @Test(dataProvider = "iterator")

    2. public void testcase2(String name){

    3. log.info(" name = [{}] " ,name);

    4. }

    运行结果:

    1. name = [延迟数据提供:0]

    2. name = [延迟数据提供:1]

    3. name = [延迟数据提供:2]

    4. name = [延迟数据提供:3]

    5. ===============================================

    6. Default Suite

    7. Total tests run: 4, Failures: 0, Skips: 0

    8. ===============================================

    其他的高级玩法

    数据提供程序可以与并行属性并行运行:

    1. @DataProvider(parallel = true)

    2. // ...

    从 XML 文件运行的并行数据提供程序共享相同的线程池,默认情况下大小为 10。可以在 XML 文件的 suite 标记中修改此值:

    1. <suite name="Suite1" data-provider-thread-count="20" >

    如果要在不同的线程池中运行几个特定的数据提供程序,则需要从其他 XML文件运行它们。

    小结

    这篇的知识点:

    • 需要参数化来创建数据驱动测试;

    • TestNG 支持两种参数化,使用 @Parameter + TestNG.xml 并使用 @DataProvider;

    • 在 @Parameter + TestNG.xml中,参数可以放在套件级别和测试级别。如果在两个地方声明相同的参数名称,测试级别参数将优先于套装级别参数;

    • 使用 @Parameter + TestNG.xml,一次只能设置一个值,但 @DataProvider 返回一个2维的 Object 数组;

    • 如果 DataProvider 存在于不同的类中,那么测试方法所在的类,DataProvider 应该是静态方法;

    • 有通过支持两个参数的 DataProvider 的方法和 ITestContext;

    • TestNG 允许我们从数据提供者返回一个 Iterator 对象,实现延迟提供数据。

    当然,DataProvider 只是从行为操作上分离了数据的提供方式,没有从根本上解决自动化测试中测试数据本身的稳定性、快速响应变化、数据丢失、数据被修改的这些难点和阻碍:

    • 比如生产数据库里的数据导入并刷新测试数据库,之前用例里使用的数据被覆盖;

    • 比如几个小组在一个系统里使用同一个测试数据库,AB组使用存在交叉,B组还要把数据改变一下再用,或者B组用完后测试数据已经发生改变;

    • 比如使用的测试数据具备时效性,状态会改变的,从 active 变成 inactive 的等;

    自动化测试的其他方面都不是什么大问题,最主要的阻碍就是测试数据本身(特别是在真实的测试环境上时)。

    本文源码:

    https://github.com/7DGroup/Java-API-Test-Examples/tree/master/springboot-testng-data-driven-demo

    参考资料:[1]:https://blog.csdn.net/LangSand/article/details/53895654 [2]:https://testng.org/doc/index.html [3]:软件测试52讲 茹炳晟
  • 相关阅读:
    Moebius实现Sqlserver集群~介绍篇
    知方可补不足~SQL数据库用户的克隆,SQL集群的用户同步问题
    从零开始学C++之动态创建对象
    [置顶] 某大型银行深化系统技术方案之二十五:性能设计之主要数量指标
    POJ 1300 Door Man
    解决SQL查询总是超时已过期
    hdu 1728 逃离迷宫(BFS)
    Nginx 负载均衡-加权轮询策略剖析
    ios 6 横竖屏转换
    firefox同步数据时无响应问题
  • 原文地址:https://www.cnblogs.com/ceshi2016/p/16716775.html
Copyright © 2020-2023  润新知