哈Ha!
我的名字叫Vitaliy Kotov,我在Badoo工作,大部分时间我都在处理自动化测试问题。 我想在本文中分享对这样一个问题的解决方案。
这将是关于我们如何组织工作与A / B测试的UI测试的过程,其中我们有很多。 我将谈论我们遇到了什么问题以及最终导致了哪些洪水。 欢迎来到猫!

直到我们开始...
测试一词在本文中很常见。 这是因为我们同时谈论UI测试和A / B测试。 我一直试图将这两个概念分开并提出思想,以便使文本易于阅读。 但是,如果在某个地方我错过了单词的第一部分并仅写了“ test”,则表示UI测试。
祝您阅读愉快!
什么是A / B测试
因此,首先,让我们定义A / B测试的概念。 这是维基百科的引文:
“ A / B测试(例如,A / B测试,拆分测试)是一种营销研究方法,其实质是将元素对照组与一组测试组进行比较,在测试组中一个或多个指标已更改,以便找出哪些更改可以改善目标” 链接 。
对于我们的项目,A / B测试的存在意味着某些功能对于不同的用户而言是不同的。 我将重点介绍几个选项:
- 该功能可用于一个用户组,但不适用于另一个用户组。
- 该功能适用于所有用户,但其工作方式不同。
- 该功能适用于所有用户,其功能相同,但外观有所不同。
- 前三个选项的任意组合。
为了使所有这些逻辑都能起作用,我们公司中有一个名为
UserSplit Tool的工具 ,我们的开发人员Rinat Akhmadeev在
本文中详细讨论了它。
现在,我们将讨论对测试部门,尤其是自动化部门进行A / B测试意味着什么。
UI测试覆盖率
当我们谈论UI覆盖率时,我们并不是在谈论我们测试的代码行数。 这是可以理解的,因为即使只是打开一个页面也可能涉及许多组件,而我们尚未进行任何测试。
在测试自动化领域的多年工作中,我已经看到了许多测量UI测试覆盖率的方法。 我不会列出所有内容,只是说我们希望通过UI测试涵盖的功能数量来评估此指标。 这不是理想的方式(我个人不知道理想的方式),但在我们的情况下却可行。
在这里,我们直接返回到本文的主题。 当每个功能根据使用用户的不同而表现不同时,如何衡量和保持良好的UI测试覆盖率?
最初的UI测试如何涵盖功能
甚至在UserSplit Tool出现在公司中并且确实存在许多A / B测试之前,我们就遵循以下策略来使用UI测试覆盖功能:仅覆盖已经生产了一段时间并且已经停产的那些功能。
都是因为更早的时候,当该功能仅在生产中时,它仍然“调整”了一段时间-其行为和外观可能会改变。 而且她也根本无法证明自己,很快就从用户的眼中消失了。 为不稳定的功能编写UI测试非常昂贵,并且尚未与我们一起实践。
随着在开发过程中引入A / B测试,起初没有任何变化。 每个A / B测试都有一个所谓的“对照组”,即看到该功能的某些默认行为的组。 编写UI测试是在他身上。 为此类功能编写UI测试时,只需记住要使用户具有默认行为即可。 我们称这个过程为A / B组的力量(来自英国的力量)。
我将更
详细地描述
力量 ,因为它仍然会在我的故事中发挥作用。
强制进行A / B测试和QaAPI
我们在文章和报告中一再谈论QaAPI。 但是,很奇怪的是,到目前为止,我们还没有写关于该工具的完整文章。 大概有一天这一空白将被填补。 同时,您可以观看我的同事Dmitry Marushchenko演讲的视频:“
4. QaAPI概念:从障碍的另一侧看测试 。”
简而言之,QaAPI允许您通过特殊的后门从测试向应用程序服务器发出请求,以便处理任何数据。 例如,使用此工具,我们为用户准备了特定的测试用例,向他们发送消息,上传照片等。
使用相同的QaAPI,我们可以强制A / B测试组; 足以表明测试的名称和所需组的名称。 测试调用看起来像这样:
QaApi::forceSpliTest(“Test name”, “Test group name”, {USER_ID or DEVICE_ID});
我们指定的最后一个参数是user_id或device_id,对此强制应开始起作用。 我们在未授权用户的情况下指定device_id参数,因为user_id参数尚不存在。 没错,对于未经授权的页面,我们还会进行A / B测试。
调用此QaAPI方法后,可以确保授权用户或设备所有者查看我们伪造的功能的版本。 这些是我们在UI测试中编写的挑战,其中涵盖了A / B测试下的功能。
因此我们生活了很长一段时间。 UI测试仅涵盖A / B测试的对照组。 然后,数量不多,而且行得通。 但是时间过去了; A / B测试的数量开始增加,并且几乎所有新功能都开始在A / B测试下运行。 仅涵盖功能的控制版本的方法使我们不满意。 这就是为什么...
为什么要涵盖A / B测试
问题一-覆盖率如我上面所述,随着时间的流逝,几乎所有新功能都开始在A / B测试下出现。 除控件外,每个功能还有一个,两个或三个其他选项。 事实证明,对于此类功能,最佳情况下的覆盖率不会超过50%,最坏情况下的覆盖率将约为25%。 以前,当此类功能很少时,这不会对总覆盖率产生重大影响。 现在-它开始渲染。
问题二-长A / B测试现在一些A / B测试需要花费一些时间。 而且我们每天继续发布两次(可以在质量保证工程师Ilya Kudinov的文章中找到“
我们如何在每天两次发布的条件下生存了两年”)。
因此,在此期间破坏某个版本的A / B测试的可能性非常高。 这肯定会影响用户体验,并否定该功能的A / B测试的全部要点:毕竟,某个功能在某些版本上的效果可能不佳,这并不是因为用户不喜欢它,而是因为它无法按预期工作。
如果我们想确定A / B测试的结果,我们一定不允许该功能的任何版本与预期的功能有所不同。
第三个问题是UI测试的相关性诸如发布A / B测试之类的东西。 这意味着A / B测试已经收集了足够的统计信息,产品经理准备为所有用户打开获胜选项。 A / B测试的发布与代码的发布异步发生,因为它取决于config的配置,而不取决于代码。
假设非控制变量获胜并且变得更好。 仅涵盖UI的UI测试会发生什么? 没错:它们会破裂。 但是,如果他们在发布版本之前一个小时休息了怎么办? 我们可以对此构建进行回归测试吗? 不行 如您所知,如果测试失败,您将走不远。
因此,您需要准备提前关闭任何A / B测试,以免影响UI测试的性能,并因此而不会影响该版本的下一个版本。
结论上面的结论是显而易见的:我们需要用UI测试完整地涵盖A / B测试以及所有选项。 这合乎逻辑吗? 是的 谢谢大家,发散!
...开玩笑! 没那么简单。
A / B测试界面
似乎不方便的第一件事是控制已经覆盖了A / B测试和功能,而尚未覆盖。 从历史上看,我们根据以下原则调用UI测试:
例如,ChatBlockedUserTest,RegistrationViaFacebookTest等。 在这里也将拆分测试的名称推到了不舒服的位置。 首先,名称将变得难以置信。 其次,必须在A / B测试结束时对测试进行重命名,这将对考虑UI测试名称的统计信息产生不良影响。
一直获取代码以调用QaAPI方法仍然是一种乐趣。
因此,我们决定从UI测试的代码中删除对QaApi :: forceSplitTest()的所有调用,并将有关需要向何处施加力的数据传输到MySQL表。 对于她,我们在Selenium Manager上做了一个UI演示文稿(我
在这里谈到了)。
看起来像这样:

在表中,您可以指示要针对哪个UI测试执行哪个A / B测试以及要应用哪个组。 您可以指定UI测试本身的名称,测试类或全部。
此外,我们可以指出此强制作用是适用于授权用户还是未经授权的用户。
接下来,我们在启动时教会了UI测试,以从该表中获取数据并强制那些与正在运行的测试或所有(所有)测试直接相关的数据。
因此,我们设法在一个地方收集了所有A / B测试操作。 现在可以轻松查看涵盖的A / B测试列表。
在那里,我们创建了一个表单,用于添加新的A / B测试:

所有这些使您能够轻松快速地添加和删除必要的作用力,而无需创建提交,等待它分解为运行UI测试的所有云,等等。
UI测试架构
我们决定要注意的第二件事是对编写用于A / B测试的UI测试的方法的修订。
简而言之,我将告诉您我们如何编写常规的UI测试。 该架构非常简单且熟悉:
- 测试类-描述了所涵盖功能的业务逻辑(实际上,这些是我们测试的脚本:做到了,看到了);
- PageObject类-此处描述了与UI和定位器的所有交互;
- TestCase类-有一些不与UI直接相关的通用方法,但是可以在多个测试类中使用(例如,与QaAPI交互);
- 核心类-编写会话,记录日志以及编写常规测试时不需要接触的其他内容是有逻辑的。
通常,此体系结构完全适合我们。 我们知道,如果用户界面已更改,则仅需更改PageObject类(而测试本身不应受到影响)。 如果功能的业务逻辑已更改,我们将更改方案。
正如我在
上一篇文章中所写,每个人都可以使用UI测试:手动测试部门的人员和开发人员。 这个过程越简单,越容易理解,与他们没有直接关系的人们就越会进行测试。
但是,正如我在上面所写,与完善的功能不同,A / B测试可以进行。 如果我们以与常规UI测试相同的格式编写代码,则在A / B测试完成后,我们将不得不从许多不同的位置永久删除代码。 您了解,对于重构,尤其是在一切都没有重构的情况下,并非总是可以分配时间。
不过,我们不想让我们的类因未使用的方法和定位器而过度增长,这将使相同的PageObjects难以使用。 如何使您的生活更轻松?
然后,PhpStorm进行了救援(感谢JetBrains的人员提供了便捷的IDE),即此
功能 。
简而言之,它允许使用特殊标签将代码拆分为所谓的区域。 我们尝试了-我们很喜欢。 我们开始在一个文件中编写针对活动A / B测试的临时UI测试,将代码区域划分为区域,指示将来应将此代码放入的类。
结果,测试代码如下所示:

在每个区域中都有一个属于特定类的代码。 当然,在其他IDE中也有类似的东西。
因此,我们用一个测试类涵盖了A / B测试的所有变体,并在其中放置了PageObject方法和定位符。 完成后,我们首先从类中删除了丢失的选项,然后根据该区域中的指示很容易地将其余代码分配到所需的类中。
我们现在如何关闭A / B测试
您不能一次将所有A / B测试纳入UI测试中。 另一方面,没有这样的任务。 自动化方面的挑战是仅快速覆盖重要且长期运行的测试。
尽管如此,在发布任何,甚至最小的A / B测试之前,我希望能够在获胜版本上运行所有UI测试,并确保一切正常进行,并且我们为100%的用户复制了高质量的工作功能。
上面提到的带有MySQL表的解决方案不适用于此目的。 事实是,如果在那里加力,它将立即开始为所有UI测试打开。 除了暂存(我们的生产前环境,我们在其中进行全套测试)之外,这还将影响针对单个任务的分支而启动的UI测试。 手动测试部门的同事将处理这些发布的结果。 而且,如果失败的A / B测试存在错误,则针对其任务的测试也将落空,并且伙计们可以确定问题出在他们的任务中,而不是A / B测试中。 因此,测试和试用可能要花费很多时间(没人会满意)。
到目前为止,我们已经进行了最小限度的更改,从而可以在表中指定目标环境:

可以在现有记录中即时更改此环境。 因此,我们只能在登台上加力,而不会影响对单个任务通过测试的结果。
总结一下
因此,在开始本故事之前,我们的UI测试仅涵盖A / B测试的主要(对照组)组。 但是我们意识到我们想要更多,并得出结论,也有必要涵盖其他版本的A / B测试。
总结:
- 我们创建了一个界面,可以方便地控制A / B测试的覆盖范围; 结果,我们现在有了有关UI测试和A / B测试的所有信息;
- 我们已经为自己开发了一种以简单有效的流程编写临时UI测试的方法,以将其进一步删除或转移到永久性人员的队伍中;
- 我们学习了如何轻松,轻松地测试A / B测试的发布,而不会干扰其他正在运行的UI测试,并且不会在Git中进行不必要的提交。
所有这些使测试自动化适应不断变化的功能成为可能,可以轻松控制和提高覆盖范围,并且不会因遗留代码而显得过分拥挤。
您是否有过乍一看将混乱的情况控制在一定范围内并简化自己和同事生活的经验? 在评论中分享。 :)
感谢您的关注! 新年快乐!