AI人工智能与软件测试

更多的测试人员,更多的报酬

关于 ai 与测试的讨论现在逐渐流行起来,目前看来观点基本是积极和激进的,大多数人认为 ai 会重新塑造测试行业,不过基于 ai 的测试探索目前看来还是有限的,我稍微总结了一下,大概分为两类。

  • 利用大语言模型的推理能力进行驱动的自动化工具;这个之前的文章已经介绍过一些了,有兴趣的同学可以翻一下之前的存档;
  • 对融合了 ai 功能的软件产品进行测试。推荐大家研究一下这篇文章,里面的一些标准步骤还是让人备受启发的。https://blog.scottlogic.com/2023/11/14/testing-LLM-based-applications-strategy-and-challenges.html。这些测试大多是对prompt的安全,边界条件以及输出的稳定性进行测试。

就这个时间节点看来,ai 在测试领域上的应用其实不算太多。另外目前对于大模型本身的测试工作也基本是众测模式,模型提供商经过基本的 fine tuning 和测试之后发布模型或者提供 api 接口,通过使用者的反馈来持续的改进模型,基本上走的是强化学习的路子,对模型的测试不依赖于测试行为,而依赖于更多样性的标记数据,所以哪家大模型能跑出来其实就是看哪家的显卡多和数据多。

最近看到一篇非常积极拥抱 ai 的测试文章,里面的观点基本没有数据佐证,先不去讨论正确与否,不过文章确实传递出了一种很强烈的乐观信号,因为这篇文章认为 ai 会带来更多的测试岗位和更高的报酬。下面是对这篇文章的翻译,https://jarbon.medium.com/ai-more-testers-more-money-045e1a34741d。先提前说明,对这种观点我持谨慎的乐观态度,尽管我一直认为从事ai其实跟我们当年做黑盒测试差不多,不过下文的描述在短期看来还是比较难达成的,未来是什么样确实比较难以预测,所以不如积极投身其中去创造未来吧。

下面是原文的翻译:

AI 裂变正在迅速到来。AI 将在软件测试领域创造新的有和无。将 AI 引入软件测试将改变测试人员、供应商和工具的工作方式。但是,这种变化不会如大多数人所担心或梦想的那样。声称 AI 很快就会简单地取代人工测试人员的工作是错误的。希望 AI 无法足够聪明地完成大部分测试工作也是错误的。将会有更多的测试工作,并且它们很快将得到更高的报酬。在这个过渡中,有些人会失去工作,但这取决于他们自己。只有思想开放、乐观的测试人员才能在这个过渡中生存下来,并且他们将得到丰厚的工作保障和报酬。

AI 对测试工作的影响

在短期内,AI 不会减少测试工作的数量 - 对测试人员的需求将会增加。许多测试人员担心 AI 会消灭他们的工作 - 这对大多数人来说是不真实的。应用 AI 于工作的“AI 辅助”测试人员将更加高效。那些能够迅速做到这一点的人将获得最多的工作保障、进步和回报。

在 10 亿美元以上的测试领域中,最大的问题可能是如何衡量价值。工程团队知道他们需要测试,但很难量化,而事实是,大多数测试工作在今天没有 AI 的情况下几乎没有什么用处。当测试人员得到 AI 的辅助时,测试人员的速度、范围和价值将增长到明显的价值点。目前,大多数软件测试仅仅涵盖基本功能和一些边缘情况,成本高昂,并拖慢了工程团队的进展。

然而,AI 辅助测试将赋予这些人类测试人员“超能力”,他们的贡献将是压倒性的明显。正如测试领域的一位朋友上周所描述的那样 - 不久之后,测试人员将穿戴 AI-“钢铁侠”装备。企业将希望增加更多的 AI 测试人员,因为他们终于看到了明显的积极回报。这些 AI 辅助测试人员将足够快,以便在当前的开发周期内发挥作用,给人足够的信心进行发布,发现对业务有影响的问题,并揭示仍待测试的内容。对于 AI 辅助测试人员的需求将增加,因为他们将为企业增加明显的价值 - 就像开发人员增加功能和修复错误一样。

AI 还意味着开发人员正在创建更多的软件。AI 辅助工程师的加速是非常真实的,而且 AI 也意味着更多的人可以创建软件。所有这些新软件都需要由更多经过 AI 增强的测试人员进行测试。

在selenium中使用AjaxElementLocatorFactory来优化PO模式

之前看到的一篇对于 po 的改进的文章,非常有启发,简单翻译改写了一下,希望对大家有帮助。本文基于 java,至于其他语言是否有类似的实现,没有具体研究过。

原文地址: http://www.eliasnogueira.com/better-page-objects-strategy-using-ajaxelementlocatorfactory-with-selenium-and-java

PO 模式是 page object factory 设计模式的简称,主要是以页面为维度来聚合一些元素的定位,让代码有更好的维护性和重用性,具体细节可以看这里:https://www.selenium.dev/documentation/test_practices/encouraged/page_object_models。这里是官方文档,非常值得精读。

Page Factory

如果你已经对 po 很熟悉了,下面的内容可以放心跳过。

下面是最基本的 Page Factory 套路,本质上是按页面去封装元素定位和操作。

public class PageObjectExample {

    private final WebDriver driver;

    public PageObjectExample(WebDriver driver) {
        this.driver = driver;
    }

    public void login(String email, String password) {
        driver.findElement(By.id("email")).sendKeys(email);
        driver.findElement(By.id("password")).sendKeys(password);
        driver.findElement(By.name("next")).click();
    }
}

上面的代码只能说懂的都懂,不过这里有个问题,在 login 方法里,我们频繁使用driver.findElement方法,这会显得有一些的啰嗦,下面是改进版本,优雅了很多。

public class PageObjectExample {

    @FindBy(id = "email")
    private WebElement email;

    @FindBy(id = "password")
    private WebElement password;

    @FindBy(name = "next")
    private WebElement next;

    public PageObjectExample(WebDriver driver) {
        PageFactory.initElements(driver, this);
    }

    public void login(String email, String password) {
        this.email.sendKeys(email);
        this.password.sendKeys(password);
        next.click();
    }
}

这里要注意的是在进行初始化的时候,需要调用PageFactory.initElements(driver, this);

测试人员必会的docker秘籍

Docker现在是许多 QA 工程师的常用工具。它用于生产环境和测试环境或两者兼而有之。docker 的文档制作精良,相对容易理解,但有时我们需要一些常用命令来解决问题。

在这里我列举一下对于测试同学来说比较值得去弄明白的 docker 秘籍。

**如何使用不同的参数运行已经启动的 docker 容器?**

可以用这个工具:https://github.com/lavie/runlike/

使用方法: runlike -p <container_name> ,这样就可以拿到该容器第一次启动时候用的具体命令了。

runlike -p testservice
docker run \
--name=testservice \
--user=test \
--env=KAFKA_HOST=172.17.0.1:9092 \
--env=PATH=/opt/java/openjdk/bin:/usr/local/sbin:/usr/local/bin \
--env=LANG=en_US.UTF-8 \
--workdir=/home/testapp \
-p 8015:8080 \
--restart=always \
--log-driver=journald \
--runtime=runc \
--detach=true \
myrepo/testservice:master-1374

这时候我们就可以修改一些参数,比如端口号信息,生活变得容易了一些。

**如何在 docker 容器中运行本地 bash 脚本?**

cat local_script.sh | docker exec <container_name> /bin/bash

如何重启或移除所有的容器?

这个技巧非常管用,推荐牢记。

docker stop $(docker ps -a -q)
docker restart $(docker ps -a -q)

**如何清理旧的 docker 镜像、容器和卷?**

docker system prune -a

**如何过滤 docker ps 命令,以仅获取所需的信息,例如容器名称、状态和镜像?**

docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Image}}"

**如何保存和恢复 docker 容器?**

docker commit -p <CONTAINER_ID> <YOUR_BACKUP_NAME>
docker save -o <CONTAINER_FILE>.tar <YOUR_BACKUP_NAME>
docker load -i <CONTAINER_FILE>.tar

如何将常用的 docker 命令简化成别名?

如果你是 docker 的重度用户的话,这个能力非常实用。

leetcode最有名的简单算法题:two sum

应该还是有很多同学在刷题找工作吧,如果大家刷 leetcode 的话,推荐的做法是从简单到难,这样一来 two sum 是大家绕不过去的最著名的简单算法题了,废话不多说,先看题目的描述。

给定一个整数数组  nums  和一个整数目标值  target,请你在该数组中找出  和为目标值 target  的那  两个  整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

提示:

  • 2 <= nums.length <= 104
  • 109 <= nums[i] <= 109
  • 109 <= target <= 109
  • 只会存在一个有效答案

**进阶:**你可以想出一个时间复杂度小于  O(n2)  的算法吗?

在2023使用playwright进行自动化测试

playwright 一直是我最看好的新一代自动化测试框架,2022 年底 playwright 在 npm 上的下载量超过了 100 万,尽管不如 selenium 和 cypress,不过势头还是相当强劲的。最近正好发现一篇文章简单的介绍了使用 typescript,pageobject 和 fixture 配合 playwright 进行用例编写的文章,这里把里面的精华拿出来分享一下。

老生常谈,playwright 的优势

  • 有个好爹,微软出品,看好长期更新维护和迭代,但也可能突然被砍掉,毕竟大公司都在裁员
  • 运行速度快
  • 自动等待元素出现
  • 报告的呈现很多元化,可以设置重试机制,捕获执行日志,截屏录屏等
  • 支持多个浏览器并行执行
  • 提供自动生成代码能力以及 Inspector GUI
  • 一套代码,跨浏览器执行的能力

目录结构

框架整体的目录结构如下。

.
├── config
   ├── global-setup.ts
   └── playwright.config.ts
├── package-lock.json
├── package.json
└── src
    ├── data
       └── data.json
    ├── fixtures
       ├── AxeFixture.ts
       └── TodoFixture.ts
    ├── pages
       └── TodoPage.ts
    └── tests
        ├── a11y.spec.ts
        └── demo-pom-todo-app.spec.ts

config 目录

  • playwright.config.ts playwright 的配置文件
  • **global-setup.ts** 在所有用例执行前运行一次,主要的目的是登录一次被测系统并保存浏览器的全局状态到 storageState.json 文件中。这样就不需要每个用例都去单独登录一次了。更多信息可以参考文档。https://playwright.dev/docs/test-advanced#global-setup-and-teardown

Page Object

po 基本上是自建框架的必选项了。具体的实现如下

强行为新项目写接口测试是一种什么样的体验

继续上次的话题,为新项目写 ui 自动化测试是一件非常有挑战的事情,写接口测试会不会容易一点呢?这次我就尝试了一下。

现阶段我们的管理端接口其实不多,就 8 个左右,所以从工作量上评估其实还可以。

测试策略

讲策略之前我们先看一下项目的简单业务属性。该项目的管理后台其实就是稍微复杂一点的增删改查。增加一条记录,编辑记录,各种组合条件查询记录,删除功能暂时没有,后面可能会跟进。

我的测试策略也很简单,首先搭建 1 个单独的测试环境,防止跟其他测试形式冲突,然后把最大的精力放在数据的准备和清理上。

  • 准备数据:为了测试查询,比较好的方式是每次都先清空数据库,然后动态创建一些固定的数据,我指的固定是比如固定 100 条,每条的排序规则,各个字段都是确定的。
  • 数据清理:完成测试后清空数据库,比如搜索测试完成之后清空数据库去测试创建和编辑,这样创建的时候就没有存量数据造成的断言干扰,就可以实现每次创建之前数据都是 0 条,创建成功之后变成 1,这样断言就相对容易,而且用例能够以随机的顺序运行,减少了依赖;

代码实现

这里最有挑战的是数据准备和清理的代码实现,我需要准备下面的数据

  • 通过接口创建一些数据到 db,之所以用接口创建是因为一些联动的操作直接写 db 的话无法触发。我们的接口是 http 的,用 python+requests 就可以了,稍微麻烦的点是构造的数据需要通过接口的有效性校验,比如时间区间之类的,因为我们的服务会跑在多个不同的国家和地区,timezone 也是需要关注的
  • 把创建成功的数据 id 以及一些需要用到的字段存到 redis 里。我习惯于用 redis 的 set,因为天生去重,并且可以使用srandmember来随机返回几条数据,在做查询校验的时候非常方便
  • 查询一些关联表的信息或者需要用到的数据,保存在 redis 里。这里我用的是 redis 的 string 类型,需要保存的信息直接序列化成 json 字符串,非常的方便;
  • 直接写 sql 做数据库的清理,直接调用 es 的 resetful api 做索引的清理。我们的查询使用的是 es,所以清理数据的时候除了用 sql 去 delete 之外,es 的 index 也是要清理的
  • 使用配置文件来进行多环境多地区的配置,比如 mysql 每个地区的配置都不一样,同样的地区不同的业务数据也在不同的库里,把配置弄起来还是很有必要的

最终实现的效果是运行TEST_ENV=test REGION=cn python data_builder.py这条命令之后就可以在对应的环境创建初始化数据了。代码比较啰嗦我就不粘贴了。

用例编写

用例编写无非是增删改查。