自动化测试无效

2020年12月30日11:04:28 发表评论 31 次浏览

本文概述

在开始之前, 我想指出, 我并不是在指一个特定的项目或任何特定的个人。我相信这些问题已经与其他人讨论过。与我合作的几乎所有自动化测试仪都破坏了肠道, 以使此故障机器正常工作。我讨厌游戏, 而不是玩家。

如果我没记错的话, 我似乎已经在另一个现实中醒了, 在现实中, 大量的金钱, 时间和资源被分配给端对端测试的编写和持续维护。我们有一个称为自动化测试器的新型开发人员, 其出现的主要原因不仅是要发现错误, 而且还要编写回归测试以消除重新执行初始手动测试的需要。

自动化回归测试在理论上听起来不错, 发现每个sprint中的每个故事都有相应的端到端测试写成的任何人都不会对新工作感到印象深刻硒webdriver.

我听说过无数关于通常使用Selenium Webdriver编写的端到端测试的故事, 由于它们的易碎性而被删除。测试自动化似乎只会导致CI确定性遭到破坏, 因为不确定性测试会使更改和进展几乎不可能。我们有测试自动化工程师, 他们太忙或不愿进行手动测试, 而由于这些表现不佳的时间和资源无法把握不确定性的测试, 从而引起了麻烦。

在失败时重新运行的测试是标准的, 甚至由某些测试运行程序提供。最缺乏经验的开发人员正在编写和维护一些最具挑战性的代码。测试代码没有受到同样的关注。我们永不停止自问, 这种疯狂的努力是否值得。我们不会跟踪指标, 只会添加更多测试。

这就像是"土拨鼠日"的奇异版本, 只是它是一个残破的版本, 而不是开始同一系列事件的新的一天。现在, 我将列出我在一个项目中遇到的重复问题, 这些项目会带来庞大的端到端测试套件的负担。

对自动化测试会发现新缺陷的期望有误

在撰写本文时, 几乎所有测试都对一组固定的输入声明了他们的期望。以下是一个简单的登录功能文件:

Feature: Login Action

Scenario: Successful Login with Valid Credentials

  Given User is on Home Page
  When User Navigate to LogIn Page
  And User enters UserName and Password
  Then Message displayed Login Successfully

功能文件以称为步骤定义的方式执行以下Java代码:

@When("^User enters UserName and Password$")
  public void user_enters_UserName_and_Password() throws Throwable {
  driver.findElement(By.id("log")).sendKeys("testuser_1");
  driver.findElement(By.id("pwd")).sendKeys("Test@123");
  driver.findElement(By.id("login")).click();
 }

仅当此有限输入集触发错误时, 此测试才会找到错误。新用户输入的字符不是testuser_1和测试@ 123不会被端到端测试所困扰。我们可以通过使用黄瓜表来增加输入的数量:

Given I open Facebook URL
 And fill up the new account form with the following data
 | First Name | Last Name | Phone No | Password | DOB Day | DOB Month | DOB Year | Gender |
 | Test FN | Test LN | 0123123123 | Pass1234 | 01 | Jan | 1990 | Male |

这些测试最有可能发现错误的时间是它们第一次运行。尽管上述测试或测试仍然存在, 但我们将必须维护这些测试。如果他们使用Selenium Webdriver, 那么我们可能会在持续集成流程中遇到延迟问题。

我们为制作了一个自定义演示.
不完全是。点击这里查看.

自动化测试无效1

可以将这些测试沿测试金字塔推到单元测试或集成测试中。

不要通过用户界面进行所有测试

我并不是说我们应该放弃端到端测试, 但是如果我们要避免维护这些通常很脆弱的测试, 那么我们应该只测试幸福的道路。我想要一个烟雾测试, 让我知道最关键的功能正在工作。在开发人员单元测试或集成测试中, 应在更细粒度的级别上处理异常路径。

登录示例中出现错误的最常见原因是用户输入。我们不应该使用硒来测试用户输入。我们可以编写廉价的单元测试来检查用户输入, 而这些输入不需要端到端测试的维护开销。我们仍然需要为幸福的道路进行一次端到端测试, 以检查它们是否都挂在一起, 但是对于特殊的路径, 我们不需要进行端到端测试。

可以并且应该将测试分解为单元测试和集成测试所承担的大部分负担。

大家都忘了测试金字塔?

Selenium Webdriver不适合使用

我以前在我的帖子中写过关于此的博客Cypress.io:硒杀手。不编写不确定的硒测试几乎是不可能的, 因为你必须等待DOM和宇宙的四个角完美对齐才能运行测试。

如果你要测试没有动态内容的静态网页, 那么硒是极好的选择。但是, 如果你的网站具有以下一种或多种情况, 那么你将不得不应对易燃性或不确定性测试:

  • 从数据库读取和写入
  • JavaScript / ajax用于动态更新页面,
  • (JavaScript / CSS)从远程服务器加载,
  • CSS或JavaScript用于动画
  • JavaScript或React / Angular / Vue等框架呈现HTML

面临以上任何条件的自动化测试人员将通过一系列等待, 轮询等待, 检查ajax调用是否完成, 检查javascript是否已加载, 动画是否已完成等来填充其测试。

测试变成了绝对的混乱和彻底的维护噩梦。在不知不觉中, 你就具有以下测试代码:

click(selector) {
    const el = this.$(selector)
    // make sure element is displayed first
    waitFor(el.waitForDisplayed(2000))
    // this bit waits for element to stop moving (i.e. x/y position is same).
    // Note: I'd probably check width/height in WebdriverIO but not necessary in my use case
    waitFor(
      this.client.executeAsync(function(selector, done) {
        const el = document.querySelector(selector)

        if (!el)
          throw new Error(
            `Couldn't find element even though we .waitForDisplayed it`
          )
        let prevRect
        function checkFinishedAnimating() {
          const nextRect = el.getBoundingClientRect()
          // if it's not the first run (i.e. no prevRect yet) and the position is the same, anim
          // is finished so call done()
          if (
            prevRect != null &&
            prevRect.x === nextRect.x &&
            prevRect.y === nextRect.y
          ) {
            done()
          } else {
            // Otherwise, set the prevRect and wait 100ms to do another check.
            // We can play with what amount of wait works best. Probably less than 100ms.
            prevRect = nextRect
            setTimeout(checkFinishedAnimating, 100)
          }
        }
        checkFinishedAnimating()
      }, selector)
    )
    // then click
    waitFor(el.click())
    return this;
  }

我注视着这段代码。除了一个巨大的大片状碎片, 还需要时间和精力才能使这个怪物存活, 这怎么可能呢?

赛普拉斯通过将自身嵌入浏览器并在与浏览器相同的事件循环中执行, 可以避免此问题, 并且代码可以同步执行。采取异步性而不必求助于轮询, 睡眠和等待助手, 这极大地增强了人们的能力。

测试的有效性未得到跟踪, 我们不会删除不良测试

测试自动化工程师非常擅长测试, 根据我的经验, 我们没有做任何工作来确定测试是否付诸实践。

我们需要用于监视测试脆弱性的工具, 如果脆弱性过高, 它将自动隔离测试。隔离会从关键路径中删除测试, 并向开发人员提交错误, 以减少脆弱性。

从地球表面消除所有不确定性测试

如果重新运行该构建是修复测试的解决方案, 则需要删除该测试。一旦开发人员进入按下"再次构建"按钮的思维方式, 对测试套件的所有信念就会消失。

重新运行失败的测试表明完全失败

测试跑步者西葫芦可以可耻地配置为在失败时重新运行:

@RunWith(Courgette.class)=
 @CourgetteOptions(
  threads = 1, runLevel = CourgetteRunLevel.FEATURE, rerunFailedScenarios = true, showTestOutput = true, ))

 public class TestRunner {
 }

在说什么rerunFailedScenarios = true是我们的测试不确定, 但是我们不在乎, 我们只是要重新运行它们, 因为希望它们下次能够正常工作。我认为这是有罪的。当前的测试自动化思想认为这种可接受的行为。

如果你的测试不确定, 即使用相同输入运行时其行为不同, 则将其删除。非确定性测试可能会耗尽项目的信心。如果你的开发人员不加思索地按下魔术按钮, 那么你已经达到了这一点。删除这些测试, 然后重新开始。

端到端测试的维护成本很高

测试维护已成为许多测试自动化计划的失败。如果与手动重新运行相比花费更多的精力来更新测试, 则测试自动化将被放弃。你的测试自动化计划不应成为高昂维护成本的牺牲品。

除了简单地执行和报告外, 测试还有很多。通常会忘记环境设置, 测试设计, 策略, 测试数据。你可以从你选择的云提供商处观看每月发票的飞涨, 这是运行每个扩展测试套件所需的资源数量。

自动化测试代码应视为生产代码

自动化测试人员通常是刚接触开发人员的新手, 突然被赋予在Selenium Webdriver中编写复杂的端到端测试的任务, 因此, 他们需要执行以下操作:

  • 不要复制和粘贴代码。复制和粘贴的代码具有自己的生命力, 绝不可能发生。我经常看到
  • 不要通过用户界面设置测试代码。我已经看过很多次了, 最终你会得到肿的测试, 这些测试会多次重新运行同一测试设置代码, 以至于为新场景编写更多测试代码。测试必须独立且可重复。每个新功能的播种或初始化应通过脚本编写或在测试之外进行
  • 不要使用线程睡眠和其他黑客。每次自动化测试人员使用时, 一只小狗都会在天堂死亡线程睡眠带着一些任意的数字, 徒劳地希望X毫秒将达到他们的期望。失败是使用的唯一结果线程睡眠

自动化测试代码需要与真实代码进行同样的审查。这些难以编写的测试方案不应成为复制和粘贴技巧的海洋, 以达到终点。

测试人员不再想要测试

我对此表示同情, 但是手动测试不如编写代码引人注目, 因此手动测试被认为已过时且无聊。手动测试后应编写自动化测试以捕获回归。我曾经使用过的许多自动化测试仪都不再喜欢手动测试, 并且它已经被淘汰了。与使用一组固定的输入编写一个测试相比, 手动测试将捕获更多的错误。

现在, 在崭新的票证或故事上编写Gherkin语法, 然后直接编写特征文件和步骤定义, 这通常是司空见惯的。如果发生这种情况, 那么将绕过手动测试, 并在实际回归之前编写回归测试。我们正在为可能永远不会发生的错误编写测试。

总结

据我估计, 我们将大量金钱和资源用于无法正常工作的事情。我从自动化测试中看到的唯一好结果是疯狂的长期构建, 并且我们使变更异常困难。

我们对自动化测试并不明智。原则上听起来不错。尽管如此, 仍然存在着太多的陷阱, 我们很快就会陷入僵局, 那里的变化令人难以忍受, 难以维持的测试由于没有充分的理由而活着。

我会给你留下这些我认为需要回答的问题:

  • 为什么没人质疑投资回报是否值得付出努力?
  • 我们为什么要让Flakey测试成为常态, 而不是例外?
  • 为什么要用相同的输入重新运行测试并获得不同的结果, 以至于我们有像西葫芦这样的跑步者可以自动执行此操作呢?
  • 为什么硒不适合目的是正常的?
  • 为什么开发人员仍在大量等待, 轮询等待和最糟糕的情况下求助线程睡眠代码急于完成任务?这是薄片的根。

日志火箭:全面了解你的网络应用

LogRocket仪表板免费试用横幅

日志火箭是一个前端应用程序监视解决方案, 可让你重播问题, 就好像问题发生在你自己的浏览器中一样。 notlogy无需猜测错误发生的原因, 也不要求用户提供屏幕截图和日志转储, 而是让你重播会话以快速了解出了什么问题。无论框架如何, 它都能与任何应用完美配合, 并具有用于记录来自Redux, Vuex和@ ngrx / store的其他上下文的插件。

除了记录Redux动作和状态外, notlogy还会记录控制台日志, JavaScript错误, 堆栈跟踪, 带有标题+正文, 浏览器元数据和自定义日志的网络请求/响应。它还使用DOM来记录页面上的HTML和CSS, 甚至可以为最复杂的单页面应用程序重新创建像素完美的视频。

免费试用

.

一盏木

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: