自动化框架参数间传递的一种最佳实践

持续坚持原创输出,点击蓝字关注我吧

作者:软件质量保障
知乎:https://www.zhihu.com/people/iloverain1024

本文的主题是ThreadLocal,作者将其用于接口自动化框架设计,并解决用例并发执行带来的线程不安全问题。

首先介绍ThreadLocal的原理与使用,其次介绍使用场景以及接口自动化的简单演示。

一、解析ThreadLocal

ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量,可以称为线程本地变量。

查看ThreadLocal实现源码,会发现有四个方法比较重要。

public T get()public void set(T value)protected T initialValue()public void remove()

下面通过实例给大家演示下ThreadLocal的原理与用法。

set就是设置值,get就是获取值,如果没有值,返回null,看上去,ThreadLocal就是一个单一对象的容器,比如:

public class ThreadLocalBasic {    static ThreadLocal<Integer> local = new ThreadLocal<>();    public static void main(String[] args) throws InterruptedException{        // main 线程,设置local值为100        local.set(100);        Thread child = new Thread(){            // Thread-0 线程            @Override            public void run(){                System.out.println(Thread.currentThread().getName() + ": "+ local.get());                local.set(200);                System.out.println(Thread.currentThread().getName() + ": "+local.get());            }        };        child.start();        child.join();        System.out.println(Thread.currentThread().getName()+ ": " + local.get());    }}

5320bfb5f3a46fee4fb6a050f84bca9b.png

通过结果发现,main线程对local变量的设置对Thread-0线程不起作用,Thread-0线程对local变量的改变也不会影响main线程,它们访问的虽然是同一个变量local,但每个线程都有自己的独立的值,这就是线程本地变量的含义。

initialValue用于提供初始值,可以通过匿名内部类的方式提供,当调用get方法时,如果之前没有设置过,会调用该方法获取初始值,默认实现是返回null。remove删掉当前线程对应的值,如果删掉后,再次调用get,会再调用initialValue获取初始值。

public class ThreadLocalInit {    static ThreadLocal<Integer> local = new ThreadLocal<Integer>(){        @Override        protected Integer initialValue(){            return 100;        }    };    public static void main(String[] args) {        System.out.println(local.get());        local.set(200);        local.remove();        System.out.println(local.get());    }}

44bf889ce8f69dbb40e9b6e5ede66ccd.png

二、ThreadLocal使用场景

日期处理

ThreadLocal是实现线程安全的一种方案,比如对于DateFormat/SimpleDateFormat,每个线程使用自己的DateFormat,就不存在安全问题了,在线程的整个使用过程中,只需要创建一次,又避免了频繁创建的开销。

public class ThreadLocalDateFormat {    static ThreadLocal<DateFormat> sdf = new ThreadLocal<DateFormat>() {        @Override        protected DateFormat initialValue() {            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");    }    };    public static String date2String(Date date){        return sdf.get().format(date);    }    public static Date string2Date(String str) throws ParseException{        return sdf.get().parse(str);    }}

三、接口自动化上下文信息

ThreadLocal的典型用途是提供上下文信息,比如在一个Web服务器中,一个线程执行用户的请求,在执行过程中,很多代码都会访问一些共同的信息,比如请求信息、用户身份信息、数据库连接、当前事务等,它们是线程执行过程中的全局信息,如果作为参数在不同代码间传递,使用ThreadLocal就很方便,这样又在并发的场景下保证了线程安全。

下面以登录接口,测试查询接口为例,登录后直接将token存入ThreadLocal的token中,然后在queryTest使用token传递给queryBook接口用于鉴权。

public class ThreadLocalDemoTest {    static ThreadLocal<String> token = new ThreadLocal<String>();    // 模拟登陆,将token set到上下文    @BeforeTest    public static void login(){        token.set(LoginService.login("admin"));    }    @Test    public void queryTest(){        String response = QueryBookService.queryBook(token.get());        Assert.assertEquals(response, "管理员查询图书");    }}

当然了,上述例子比较简单,线程本地变量仅存储token;如果需要存储更多的信息,那该咋办?

我们可以对ThreadLocal进行封装成ThreadLocalUtil,开发一个用于存储map的put和取map的getContextMap方法。

private final static ThreadLocal<Map<String, Object>> THREAD_CONTEXT = new MapThreadLocal();public static void put(String key, Object value) {        getContextMap().put(key, value);}static Map<String, Object> getContextMap() {        return THREAD_CONTEXT.get();    }

用例实践:

public class ThreadLocalTest {    // 模拟登陆,将token set到上下文    @BeforeTest    public static void login(){        ThreadLocalUtil.put("token", LoginService.login("admin"));        ThreadLocalUtil.put("username", "软件质量保障");    }    @Test    public void queryTest(){        String response = QueryBookService.queryBook(ThreadLocalUtil.getContextMap().get("token").toString());        Assert.assertEquals(response, "管理员查询图书");    }}

- END -


下方扫码关注 软件质量保障,与质量君一起学习成长、共同进步,做一个职场最贵Tester!

  • 后台回复【测开】获取测试开发xmind脑图

  • 后台回复【加群】获取加入测试社群!

往期推荐

聊聊工作中的自我管理和向上管理

经验分享|测试工程师转型测试开发历程

聊聊UI自动化的PageObject设计模式

细读《阿里测试之道》

我在阿里做测开

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

软件质量保障

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值