AI人工智能与软件测试

关于生成式AI在测试行为中的思考

看到了一篇讨论测试和 AI 的文章,有些观点确实是非常正确的,顺手翻译了一下,供大家参考。

我自己读了两遍,发现翻译的版本措辞不够通顺,还是直接给个省流版本好了。

省流

  • AI 生成的代码开发可能不理解其中的原理,这就为代码变更埋下了隐患,毕竟代码等于是抄的,改抄过来的东西往往不容易
  • AI 每次生成的代码可能风格都不一样,这样用的越多,代码风格百花齐放的可能性就越大,这样在团队协同的时候会带来麻烦
  • AI 生成的代码不好维护,集成进现有代码的难度其实很大
  • AI 写用例很菜,一些异常情况可能考虑不到
  • AI 生成的测试用例是没有测试模型指导的,所以随机性很大,这就导致了用例对功能的覆盖率可能不会很高
  • AI 生成的代码可能引入过时的依赖库和解决方案,从而让团队背上了技术债
  • 泛化型的 AI 在代码和测试用例生成时可能不会给出最正确的决策,这很好理解,毕竟有些训练数据本身可能质量不高,这就造成了生成的内容质量低下
  • 招聘问题。是招会写代码的人还是招会用 ai 的人?

随着生成式 AI 及其对各行各业的影响成为热门话题,我想探讨一下它将如何影响软件测试,主要基于使用这类 AI 可能带来的风险。了解这些新工具的潜在风险,有助于我们获得相关信息,并思考将其融入团队时需要采取的测试策略。

代码质量不如亲自编写

生成式 AI 通过分析互联网上的内容来根据提示创建代码,这意味着你会继承其他开发者的编码风格和特点。这可能导致我们难以理解为我们生成的代码,从而增加维护和继承的难度。另一个风险是我们可能会想当然地认为 AI 按照我们的要求执行,而不去验证(因为代码难以理解)。

这不仅影响产品代码,也会影响测试代码的生成。为应对这个问题,我们可以对代码进行全面的静态分析和重构,以提高其可读性。

编码习惯和风格不一致

与上述情况类似,AI 会采用各种程序员的风格和习惯。这意味着每次要求生成代码时,可能会得到不同的实现方式或编码风格。这同样会影响代码的可维护性和可继承性,缺乏一致性也使问题更难被发现。代码所有权也可能成为问题,因为难以确定是团队中谁的代码。在代码集成方面,不同的编码风格可能难以协调,函数行为可能相互矛盾。

解决方案仍然是进行更多的静态分析和代码重构,以及对函数行为进行基于代码的测试,以确保代码的可理解性和正确性。

更高的维护成本

生成的代码可能难以与现有代码很好地融合,因此我们可能不得不替换而非添加代码。这可能导致现有的代码测试失效,增加代码行为偏离预期的风险。替换现有代码还意味着必须重新测试现有功能,特别是如果我们失去了贴近代码的测试,这将增加测试所需的时间。

对代码(或生成的测试)缺乏理解意味着每次修改代码库时都需要花更多时间进行静态分析。一种应对方法是为测试建立独立的代码库,这样对代码的修改就不会影响测试。测试人员还必须人工审查生成的测试,确保它们与当前的代码库相符。

生成的代码质量如同实习生水平

生成式 AI 创建的软件代码或自动化测试可能只达到实习生的水平。它会完成你明确要求的内容,但可能忽视细节或异常情况。这存在测试覆盖不全的风险,也可能无法发现更深层次的问题。任何不确定性都可能导致 AI 做出与你意图不符的假设,从而影响功能表现。

应对这种情况的方法是确保继续进行探索性测试和人工测试。测试人员不仅要审查生成的测试,还要继续测试 AI 已涉及功能的准确性。我们还必须善于减少不确定性,并以不留任何假设空间的方式记录所有要求,以便输入到 AI 中(不要认为它会有常识并知道失败应该导致错误)。

缺乏测试模型

由于你可能使用简短的提示而非详细的测试用例,你可能对测试覆盖率缺乏心理预期。如果过度依赖低代码或无代码测试工具,我们可能对代码/软件的行为缺乏深入理解。这可能影响软件的可维护性,并可能导致遗漏或错误测试边缘情况和功能。

为应对这些风险,我们需要制定计划来探索代码和功能,以了解其工作原理。这种理解可以用于改进生成的自动化测试,并指导我们知道应该测试什么以及如何测试。

引入不良依赖项导致技术债务

生成式 AI 可能会引入过时的库,这可能导致代码不受支持或无法正常工作。尝试更新生成的代码可能会失败,或者如果 AI 引入了我们不知道会发生变化的库,就存在代码突然停止工作而我们不知原因的风险。AI 使用的库可能存在安全漏洞,如后门或恶意代码,我们必须诊断和修复这些问题。

我们必须确保团队分析所使用的库,并在生成的代码中记录这些库,以便检查其有效性。还需要对所有生成的代码进行静态分析,以测试是否存在漏洞和安全缺陷(包括对 AI 创建的功能进行渗透测试)。

AI 可能做出不直观的决策

所使用的 AI 可能会在创建代码、测试内容或测试方法上做出糟糕的决定。如果代码不直观,我们可能无法从代码中推断 AI 所做的假设。这带来了无法理解或维护代码和测试的风险,以及得到无用的测试或遗漏关键内容的风险。

跟线上事故相关的几个指标

最近业界比较流行面向指标的开发,据我所知在一些大厂,所有的开发过程指标和结果指标都要被明确定义出来并进行统计。

这里无意去罗列各种过程指标和结果指标,只想稍微分享一下跟线上事故相关的几个指标。

事故量度指标

事故量度指标帮助我们评估整个系统的表现。它们通过事故数量和时间频率,反映了系统的可靠性。然而,事故量度指标并不能让我们知晓我们对事故预案的准备程度。

✅ 告警转化率(Alert-to-Incident Ratio)

这个指标也被称为告警转换率,它对团队的健康状况至关重要。虽然我们强调快速响应每一个告警的重要性,但过多的告警可能会适得其反。当告警数量过多时,团队成员可能会产生"告警疲劳",这不仅会影响团队的整体效率,还可能削弱我们的可靠性策略。

长期处于高压状态下的团队成员容易感到精疲力竭,当真正严重的事故发生时,他们可能无法以最佳状态应对。这就是为什么我们需要密切关注告警转换率的原因。

如果我们发现大量告警最终并未演变成实际事故,那就意味着我们需要重新审视告警机制了。找到合适的平衡点并非易事,这需要我们不断调整和优化可观测性工具链。正因如此,持续监控和分析告警转换率变得尤为重要,它能帮助我们及时发现问题,并做出必要的调整。

👻 单位时间事故数(Incidents Over Time)

这个指标简单地统计了特定时期内的事故发生次数。虽然看似直观,但单独使用时往往缺乏深度洞察。有趣的是,这个数据常常引起 SRE 团队之外人员的关注,但我们要警惕它可能变成一个华而不实的指标。

需要注意的是,某个月份或季度的事故数量并不能直接反映系统的可靠性。这些数字的波动可能与业务的季节性特点有关,或者受到一些我们无法掌控的外部因素影响。

不过,跟踪事故数量的变化趋势确实有其价值。它能帮助我们评估当前的值班安排是否合理,以及是否需要增加人手支持。为了保护团队不被过度劳累,很多公司都会设定每个值班轮次最多处理 2 起事故的上限。这种做法既能确保及时响应,又能避免团队成员疲惫不堪。

✅ 平均故障间隔时间(MTBF)

Mean Time Between Failures

MTBF(平均故障间隔时间)是一个重要的可靠性指标,它计算的是系统或某个组件在两次故障之间的平均时间。想象一下工厂里的安全记分牌,上面记录着"已安全运行天数",MTBF 的概念与之类似。这个指标之所以能够很好地反映系统可靠性,是因为它直观地展示了系统出现故障的频率。

MTBF 的应用非常广泛。通过分析这个指标,我们可以:

  1. 对系统未来的可靠性进行预测
  2. 制定更加合理的预防性维护计划
  3. 比较不同组件的可靠性表现

特别值得注意的是,当我们发现某些组件的 MTBF 明显低于其他部分时,这就为我们提供了强有力的数据支持。利用这些数据,我们可以说服相关方投入资源,对这些问题频发的组件进行深入分析和改进。这种数据驱动的决策方法,能够帮助我们更加精准地提升系统的整体可靠性。

事故响应指标

事故响应指标是衡量我们处理事故能力的重要标尺。通过这些指标,我们可以清晰地看到团队在应对事故时的表现,同时也能发现我们的工具链中可能存在的不足之处。这些洞察为我们持续改进事故响应流程提供了方向。

👻 平均确认时间(MTTA)

Mean Time To Acknowledge

想知道你的团队对告警的反应有多快吗?平均确认时间(MTTA)就是答案。这个指标精确地测量了从系统发出告警到团队成员确认接收之间的时间。

虽然 MTTA 是个重要指标,但它更多地反映了你的值班系统的设置是否合理。如果你发现 MTTA 高于预期,那可能就需要重新审视你的值班轮换安排和升级策略了。

不过,使用 MTTA 时要小心,因为它容易被值班工程师"钻空子"。如果你为 MTTA 设定了具体目标,工程师们可能会为了达标而快速确认告警,但这并不能保证他们会有效地处理整个事故直到解决。换句话说,快速确认不等于高效解决。

因此,在使用 MTTA 时,我们需要全面考虑,将其与其他指标结合使用,以获得更全面的事故响应效率评估。

✅ 平均解决时间(MTTR)

Mean Time To Resolve

在所有事故响应指标中,MTTR 无疑是当之无愧的明星。它代表平均解决、恢复或修复时间。几乎所有推销 SRE 相关工具的人都会强调 MTTR 的重要性,因为从一线事故指挥到高层管理,每个人都关心一个核心问题:我们能多快解决问题?

充分发挥 Selenium 4 的潜力

selenium 4 的新功能,不是非常惊喜,不过确实比较实用了。

在瞬息万变的网络自动化领域,Selenium 一直是主要参与者。随着 Selenium 4 的发布,其功能得到进一步增强,引入了前沿特性,简化了测试流程并提高了效率。Chrome DevTools 和 BiDi API 的集成不仅增强了 selenium 的技术能力,还为管理自动化项目的经理们带来了战略价值。

Chrome DevTools 协议:深入浏览器自动化

Selenium 4 与 Chrome DevTools 协议 (CDP) 的集成为自动化测试人员开启了无限可能。通过直接与浏览器底层协议交互,CDP 实现了全面的网络和性能监控、控制台日志访问以及高级调试能力。

想象一下,你需要测试应用在不同网络条件下的表现。利用 CDP,你可以模拟各种网络速度,分析应用如何处理缓慢或不稳定的连接。这一功能确保你的网络应用具有韧性,能够为各种网络条件下的用户提供最佳性能。

CDP 还支持以下强大功能:

  1. 模拟网络条件: 模拟离线模式、慢速网络等情况,测试应用的适应能力
  2. 访问控制台日志: 直接捕获和分析控制台日志,便于调试和验证 JavaScript 错误
  3. 性能指标: 收集详细的性能指标,识别瓶颈并优化加载时间
  4. 安全测试: 监控和操作 cookie,追踪混合内容等安全问题,验证 HTTPS 配置

启用网络拦截的示例代码:

public class ChromeDevToolsExample {
    public static void main(String[] args) {
        System.setProperty("webdriver.chrome.driver", "path/to/chromedriver");
        ChromeOptions options = new ChromeOptions();
        ChromeDriver driver = new ChromeDriver(options);

        DevTools devTools = driver.getDevTools();
        devTools.createSession();

        // 启用网络
        devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));

        // 添加网络请求监听器
        devTools.addListener(Network.requestWillBeSent(), request -> {
            System.out.println("请求 URL: " + request.getRequest().getUrl());
        });

        driver.get("https://www.example.com");

        driver.quit();
    }
}

在这个例子中,我们启用了网络拦截来捕获浏览器发出的所有网络请求。这对于验证是否发出了正确的网络请求以及调试资源加载问题特别有用。

7大开源 CI/CD 工具 2024版本

现在很多测试岗位需要测试同学有 CI/CD 流水线的搭建经验,这里给大家推荐一下常用的 7 大 CI/CD 工具,覆盖了代码管理,ci/cd 集成,静态代码扫描,容器安全扫描,测试用例管理,性能测试等方向,值得收藏。

SonarQube: 代码质量的守护者

SonarQube 是一款卓越的代码质量和静态分析工具。

它通过发现 bug、漏洞和代码质量隐患,帮助开发者维护高水平的代码标准。SonarQube 凭借其直观的界面和全面的报告,确保您的代码库保持整洁和易于维护。

我采访过的许多专家都表示,我会喜欢上 SonarQube,因为它能帮助改进代码并推广良好的编码习惯。

SonarQube 的优点:

  • 静态代码分析
  • 检测 bug 和漏洞
  • 追踪代码质量隐患
  • 生成全面的质量报告

目前在 GitHub 上拥有 8.8k 星标。

GitLab: 一体化 DevOps 平台

GitLab 不仅仅是版本控制工具。

我交流过的专家认为,它是一个完整的 DevOps 平台,包含 CI/CD 流水线,为众多团队提供一站式解决方案。此外,GitLab 的集成方式简化了工作流程,增强了开发和运维团队之间的协作。

GitLab 的优点:

  • 集成版本控制
  • 内置 CI/CD 流水线
  • 协作开发环境
  • 精简的 DevOps 工作流程

目前在 GitHub 上拥有 5.1k 星标。

Gitleaks: 保护密码信息

在 DevOps 中,安全至关重要,Gitleaks 可以扫描和检测代码中的硬编码密码。这个工具有助于防止 API 密钥和密码等敏感信息意外泄露,提高整体安全水平。

如何优雅的测试cli应用

之前写过一篇文章讨论如何去做 hello world 的单元测试,当时想到的一个方法是将 hello world 抽象成 1 个函数,这个函数返回 hello world 字符串,然后测试这个函数的返回值就好了,代码大概如下所示。

def hello_world():
    return "hello world"

前几天看到 rust cli 手册里的一个做法,比上面的方案更加的合理,这里忍不住分享一下。

更优雅的解决方案

测试功能有两种互补的方法:测试构建完整应用程序的小单元,这些称为"单元测试"。还有从"外部"测试最终应用程序,称为"黑盒测试"或"集成测试"。让我们从第一种开始。

为了弄清楚我们应该测试什么,让我们看看我们的程序功能是什么。主要来说,grrs 应该打印出与给定模式匹配的行。因此,让我们为此编写单元测试:我们要确保我们最重要的逻辑能正常工作,并且我们要以一种不依赖于周围任何设置代码(例如处理 CLI 参数)的方式来做到这一点。

回到我们对 grrs 的第一个实现,我们在 main 函数中添加了这段代码:

// ...
for line in content.lines() {
    if line.contains(&args.pattern) {
        println!("{}", line);
    }
}

遗憾的是,这不太容易测试。首先,它在 main 函数中,所以我们不能轻易调用它。这可以通过将这段代码移到一个函数中来轻松解决:

fn find_matches(content: &str, pattern: &str) {
    for line in content.lines() {
        if line.contains(pattern) {
            println!("{}", line);
        }
    }
}

现在我们可以在测试中调用这个函数,看看它的输出是什么:

没想到测试知识库竟然还真有人访问

之前翻译了一版我认为是史上最全的测试 wiki,并把内容作为测试知识库放到了 itest.info,也就是重定向学院的网站上面。

一段时间过去了,前几天我偶然看了一下百度统计里的结果,发现这些 wiki 内容竟然已经有自然流量了,尽管翻译的效果不是很好,但有访问就是好事,可以重点去优先那些大家都在搜索的页面了。

热门内容

我稍微统计了一下,热门的测试知识点有下面几个。

测试规范(测试规格说明书)

可能是这个条目的英文把大家给迷惑了,英文叫做 test specification,直接翻译过来就是测试规范。

大家在工作中遇到一些质量管理的问题时总会想着去学一下别人是怎么做的,有没有好的管理流程和质量规范。

但这个条目的测试规范不是我们所理解的在测试里的准入和准出标准,或者跟流程相关的内容,这里的测试规范实际上是测试规格说明书。它包含下面这些内容。

  • 测试范围:明确定义需要测试和不需要测试的内容,确保测试的重点和效率。
  • 测试目标:概述测试的目标和目的,提供方向和成功标准。
  • 测试标准:指定通过/不通过的标准,包括进入和退出条件。
  • 测试环境:描述进行测试时的硬件、软件、网络配置和其他条件。
  • 测试用例:详细描述每个测试,包括步骤、预期结果和测试数据。
  • 可追溯矩阵:将测试用例与需求关联,确保覆盖和责任。
  • 测试交付物:列出测试过程的输出,如报告、日志和缺陷摘要。
  • 资源规划:识别测试所需的人员、工具和其他资源。
  • 进度和估算:提供测试准备、执行和评估的时间表。
  • 风险分析:评估测试过程中潜在的风险,并制定缓解策略。
  • 假设和依赖:记录进行测试所需的前提条件或假设。

这更像是描述测试管理理念的终极文档。包含了测试范围,测试规划,测试环境和测试产出等,是个纲领性质的东西。

如果大家有搭建测试团队或者团队管理的需求,可以参考这个条目的内容,我已经重新翻译过了,尽量做到英文内容的忠实还原。

地址: https://www.itest.info/wiki/test-specification

故障注入测试

故障注入测试(FIT)是一种测试人员故意向系统引入错误,以评估其健壮性和错误处理能力的方法。这种技术通过模拟故障来观察系统在意外情况下的表现,确保它能够优雅地处理和恢复故障。

这个条目也是大家热搜的内容,这是因为近年来故障注入的好处越来越被更多人知晓。

故障注入测试的主要好处包括:

• 增强系统稳定性:通过故意引入故障,可以在不利条件下测试系统,确保它能优雅地处理意外情况。

• 提高容错能力:它验证了故障处理机制的有效性,从而打造出更具弹性的软件。

• 系统加固:让系统暴露于故障中有助于识别并加强薄弱环节,降低生产环境中出现故障的可能性。

• 提升可靠性:通过确认系统在故障条件下的正确行为,整体可靠性得到提高。

• 改善风险管理:有助于识别潜在风险及其影响,从而制定更好的缓解策略。

• 主动发现问题:故障注入测试能发现常规测试可能无法发现的隐藏 bug。

• 验证监控和告警:确保监控系统能按预期检测并提醒故障。

• 符合行业标准:某些行业要求验证容错能力,这可以通过故障注入来实现。

• 节省成本:早期发现故障可以节省软件开发生命周期中与停机时间和后期修复 bug 相关的成本。

• 洞察系统行为:它提供了对系统在压力下行为的深入理解,可以指导未来的开发和测试工作。

该条目除了解释了故障注入的原理和概念,还推荐了一些常用工具。

地址: https://www.itest.info/wiki/fault-injection-testing

基准测试

这是在性能测试中经常引入的概念。

我们可以在某个时间点以当时系统的性能作为基准,然后每次发布之前都去做一次性能测试,从而对比系统的性能有没有劣化,如果有的话则要进行修改和优化。

地址: https://www.itest.info/wiki/baseline-testing

背靠背测试

这个我确实不知道,之前也没听说过。

背靠背测试(Back-to-back testing)是一种软件测试方法,它涉及到比较两个不同版本(通常是现有系统)的输出,以验证它们在一系列测试用例下的行为是否相同。这种测试方法在将遗留系统迁移到新平台或重构代码时特别有用,以确保新系统的行为与旧系统一致,同时避免引入回归错误。