TestNG多线程安全吗?ThreadLocal:有我还能不安全?

Hanna ·
更新时间:2024-11-13
· 711 次阅读

目录一、背景介绍二、TestNG多线程详解2.1 TestNG多线程实现2.2 TestNG多线程效果演示三、ThreadLocal3.1 ThreadLocal概念3.2 具体实现 一、背景介绍

    在使用Selenium+TestNG做WebUI自动化过程中,为了能够加快WebUI自动化测试的速度,减少测试执行时间。
    利用TestNG多线程并发测试的特性,设置了对应的线程数的并发。这样一来,测试过程中就会创建多个driver,如何保证多个driver之间不相互影响?保证对浏览器1的操作不会出现在浏览器2上?所以就使用到ThreadLocal这个类去保证线程安全。

二、TestNG多线程详解

    说到TestNG,就一般会拿TestNG与Junit来比较。但是在数据驱动、多线程并发测试这方面,TestNG自带这方面的功能,更加便捷;而Junit却需要三方工具来实现。

2.1 TestNG多线程实现

实现TestNG多线程最常见的一种方法为:testng.xml文件配置。我们可以在suite、test标签下设置parallelthread-count属性的值。
2.2 TestNG多线程效果演示 创建Test1这个类 public class Test1 { @Test public void test1(){ long id=Thread.currentThread().getId(); System.out.println("test1.1 Thread id is:"+id); } @Test public void test2(){ long id=Thread.currentThread().getId(); System.out.println("test1.2 Thread id is:"+id); } @Test public void test3(){ long id=Thread.currentThread().getId(); System.out.println("test1.3 Thread id is:"+id); } } 创建Test2这个类 public class Test2 { @Test public void test1(){ long id=Thread.currentThread().getId(); System.out.println("test2.1 Thread id is:"+id); } @Test public void test2(){ long id=Thread.currentThread().getId(); System.out.println("test2.2 Thread id is:"+id); } @Test public void test3(){ long id=Thread.currentThread().getId(); System.out.println("test2.3 Thread id is:"+id); } } 创建testng.xml(不添加多线程并发参数)

    运行testng.xml,输出结果如下。结论:每个测试方法输出的Thread id相同

test1.1 Thread id is:1 test1.2 Thread id is:1 test1.3 Thread id is:1 test2.1 Thread id is:1 test2.2 Thread id is:1 test2.3 Thread id is:1 修改testng.xml(添加多线程并发参数)

    运行testng.xml,输出结果如下。
    结论:每个test标签下的方法在同一个线程中执行。不同test标签下的方法所在线程不同。启动两个线程,一个线程负责执行test1这个中的方法,另一个线程负责执行test2这个中的方法,两个线程同时并行。

test1.1 Thread id is:11 test2.1 Thread id is:12 test2.2 Thread id is:12 test1.2 Thread id is:11 test2.3 Thread id is:12 test1.3 Thread id is:11 三、ThreadLocal 3.1 ThreadLocal概念

    ThreadLocal类的相关概念可以参考:https://www.jianshu.com/p/6fc3bba12f38
    Threadlocal是一个线程内部的存储类,可以在指定线程内存储数据,数据存储以后,只有指定线程可以得到存储数据。做个不恰当的比喻,从表面上看ThreadLocal相当于维护了一个map,key就是当前的线程,value就是需要存储的对象。

3.2 具体实现

具体实现可以参考我博客链接:https://blog.csdn.net/qq_37688023/article/details/105592464

封装ThreadLocalUtil类 public class ThreadLocalUtil { /** * 设置当前线程变量 * @param threadLocal 线程名 * @param value 线程的值 */ public void setThreadValue(ThreadLocal threadLocal, T value){ if (threadLocal.get()==null ){ threadLocal.set(value); } } /** * 获得当前线程变量的值 * @param threadLocal 线程名 * @return 返回当前线程的值 */ public T getThreadValue(ThreadLocal threadLocal){ return threadLocal.get(); } } DriverBase类(封装产生driver,并提供相关方法) @Slf4j public class DriverBase { /*声明一个driver对象*/ private WebDriver driver; /*创建一个ThreadLocalUtil对象*/ private static ThreadLocalUtil driverThreadLocalUtil = new ThreadLocalUtil(); /*创建一个ThreadLocal对象*/ private static ThreadLocal threadDriver = new ThreadLocal(); public void test1(){ /* 省略代码 */ driverThreadLocalUtil.setThreadValue(threadDriver, new ChromeDriver(chromeOptions)); /* 省略代码 */ } /** * 获得driver * */ public WebDriver getDriver(){ return driverThreadLocalUtil.getThreadValue( threadDriver ); } /** * 设置driver * */ private void setDriver(WebDriver driver){ this.driver = driver; } /** * 关闭driver * */ public void stopDriver(){ setDriver( getDriver() ); setBrowseName( getBrowseName()); if(driver != null){ driver.quit(); log.info("成功关闭" + browseName + "浏览器"); /*最后通过remove方法去掉对应的线程组*/ threadDriver.remove(); threadBrowseName.remove(); } } } BaseTest类(实际调用相关方法) public class BaseTest { /*创建DriverBase对象*/ public static DriverBase driverBase = new DriverBase(); /*创建driver对象*/ public WebDriver driver; /* 省略代码 */ /**创建指定浏览器的driver对象/ driverBase.randomOpenBrowse(browseNumber, remoteIP, browserVersion); /* 省略代码 */ /*获取对应driver*/ driver = driverBase.getDriver(); } 丶YF丶 原创文章 21获赞 53访问量 1万+ 关注 私信 展开阅读全文
作者:丶YF丶



threadlocal testng 线程安全 线程

需要 登录 后方可回复, 如果你还没有账号请 注册新账号