e2e 测试应该将数据保存在真实数据库中吗?

Should e2e tests persist data in real databases?

我已经阅读了很多关于 e2e 测试的文章,但我无法理解的一件事是 "real" e2e 测试应该如何进行。

无论我使用何种工具进行 e2e 测试,我发现大多数情况下它们都在本地、开发或 alpha 环境中运行。

如果我的应用程序有身份验证,我是否应该在数据库中创建一个具有有效凭据的 "test" 用户?我应该为 Alpha 甚至生产环境这样做吗?该测试用户还可以如何登录我的应用程序?

假设我有臭名昭著的 TODO 应用程序。我有一个让用户登录的测试。登录后,我想测试用户是否能够创建 TODO。此 TODO 保存在数据库中。

在测试 运行 之后,我应该 运行 删除 e2e 测试期间创建的数据吗?或者我应该在保存之前拦截请求并模拟响应(这将是 e2e 测试的反模式)?

End-to-end testing involves ensuring that the integrated components of an application function as expected. The entire application is tested in a real-world scenario such as communicating with the database, network, hardware and other applications

Definition of Technopedia

端到端测试是最抽象的一种测试。它测试集成组件的“流程”和“完整性”。或多或少,作为测试,它是一个完整的黑盒,所有部件都应该可以互换。集成测试,检查代码组件是否可以互换。 E2E 在测试历史中排名更高(nginx 或 Apache?PHP 或 Java?Ms oder MySQL?)

此外,E2E 测试的定义是业务需求的直接翻译,或多或少由需求工程流程预定义。

例如,Gherkin 是一种将用例转化为功能和场景的语言。示例:

Feature:  Login functionality of social networking site Facebook. 
Given:  I am a facebook user. 
When: I enter username as username. 
And I enter the password as the password 
Then I should be redirected to the home page of facebook 

一个用法 case/feature it self 可能由几个或多个句子组成,具体取决于主题的复杂程度。无论如何:它应该完全独立于您的应用程序。

如何处理测试由您决定并取决于您的应用程序:

您可能会发现某些情况(注册用户?)或者您可能想使用每日 Cron 清理数据库?

此外,为每个功能编写测试对性能要求很高。大多数时候,您为演练(您的应用程序最重要的部分——钱的来源)或功能编写这些测试,这些测试非常重要,但从未被积极测试(cookie 信息、取消订阅电子邮件、法律信息等) .)

我目前在一家大型知名公司的测试工具和框架团队工作。所以虽然我不是专家,但这是我工作的一部分。我将专门讨论网络测试。 iOS 和 Android 等原生应用的测试有些不同,我对这些方面不是很熟悉。

e2e(端到端)和集成测试之间的术语在某种程度上可以互换,而单元测试有更具体的定义。

通常 e2e/integration 测试应该 运行 在开发和生产环境中可用。根据您的设置,您的开发环境可能正在使用您的生产数据库的一些半频繁更新的快照。在其他情况下,您的本地环境可能会影响实际的生产数据库。两种方法都有 pros/cons,但这在很大程度上取决于您公司或项目的规模。例如,如果你在一家拥有专门团队的大公司,你可以看到每天有许多更改影响生产数据库,而在一个小团队中,生产数据库的每周快照可能足以在本地进行测试。 一世 在基础级别,所有集成测试都应该被视为真实的。在处理 Web 应用程序时,我们必须考虑许多其他因素,例如不同的 Web 浏览器、网络 activity / 可用性等。因此,为 api 调用模拟数据将允许进行超快速测试,但随后又增加了另一层复杂性,以确保模拟与真实世界的数据库保持同步。

运行 本地集成测试应该或多或少地对您的开发服务器做同样的事情,他们将对登台和生产做同样的事情。除了让应用程序检测它是否在开发、暂存或生产环境中 运行 以切换 URL 和各种凭据外,应用程序应该以完全相同的方式运行.

关于您关于身份验证的问题,答案是肯定的。让我们看两个显示不同注意事项的示例。

假设您的项目很小。您在生产环境中创建了一些真实帐户,您的数据库每周都会获取快照以供在本地开发环境中使用。您只需 运行 根据需要与其中一个或多个用户进行集成测试。由于本地测试只会影响您的本地数据库,因此您无需担心生成的数据,因为它不会影响生产。您团队中的其他工程师可以使用相同的用户而不必担心。如果一位工程师对数据库架构、ORM 等进行了一些更改,那么每个人都将获得数据库快照的新副本并继续工作。

现在是另一个极端。假设你的项目很大。每天都有数百万用户和数百名员工共同对代码库和数据库进行更改。有多种方法可以设置基础设施来处理各种工程任务。数据太多,数据库更改太频繁,无法使用本地快照。在这种规模下,您可能会在每次提交时进行持续集成和 运行 测试。您希望这样做,以便传入的更改不会进入生产并导致重大问题。您可能 运行 将您的本地开发环境与不断更新的登台数据库,甚至可能与您的生产数据库本身结合起来。 (尝试规划暂存数据库,因为它避免了很多其他问题。)

现在,只有一小部分专门的测试用户开始成为一个问题。测试一直在 运行 进行,既有自动化的,也有数十名工程师进行的,他们都在做自己的工作。由于暂存数据库可能是共享的,因此您很容易开始遇到奇怪的冲突,因为同一个测试用户正在做各种各样的事情并开始导致测试失败。我见过的一个很好的解决方案是一种测试帐户结帐服务器。您创建了 100 个或 1000 个(或更多)测试用户帐户。当您的集成测试 运行 时,它们实际上是从服务器签出一个测试用户帐户。测试完成后,集成测试会清除他们对该用户所做的任何更改,并告诉结帐服务器该用户再次空闲。然后它随机被 someone/something else 签出,循环继续。

因此,与您的问题直接相关的要点:

  1. 您应该始终拥有与普通用户帐户完全相同的专用测试用户帐户,专门用于测试。
  2. 根据团队和项目的规模,小的话几个专用账户就可以了。如果工作规模更大,您需要更多专用测试帐户,并且可能需要一种自动化服务,允许个人测试 运行 根据需要检查用户。
  3. 测试应始终自行清理。如果测试创建了一个存储在数据库中的 TODO。当测试完成 运行ning 时,应该从数据库中删除该 TODO。如果您不坚持这一点,您最终会 运行 陷入数据不一致的错误和问题。上帝禁止这种情况发生在生产中。
  4. 只担心单元测试的模拟数据,除非你在一个非常好的和专用的工程环境中工作,在那里你有专门的人员致力于使数据库模拟始终保持最新。如果您可以 做到这一点,您的集成测试将非常快,您实际上不必担心数据库的事情。但是,如果没有专门的支持,很难随着时间的推移保持这种状态。

I've been reading a lot about e2e testing and one thing I cannot understand is how "real" should e2e tests be.

E2e 应尽可能模拟生产系统,此外,您还可以使用 e2e 自动化来重现任何生产问题,例如数据,

Regardless of the tools I use for the e2e tests, I've seen that most of the time they hit either local, development or alpha environments.

e2e 自动化必须适用于任何 resources/database/datatsore/message 总线等,以及任何环境,包括 local/remote 或云平台

If my application has authentication, should I create a "test" user with valid credentials in the database? Should I do that for Alpha or even Production environments? How else would this test user login into my application?

只要应用程序凭据是应用程序配置的一部分,您就可以灵活地控制专用于测试的凭据。我强烈推荐 运行 并行全自动端到端专用基础设施,它不会泄露或共享生产机密。

Say I have the infamous TODO app. I have a test that logs the user in. After logging in, I want to test that the user is able to create a TODO. This TODO is saved in a Database.

通过端到端测试,您有兴趣识别所有应用输入(如 UI 交互或 REST/HTTP 请求)、配置文件和带有验证规则的输出。这包括 UI 变化,log/messages 产生,datastore/database 变化。

After running the tests, should I run something to remove the data created during e2e tests? Or should I intercept the request just before saving it and mock the response (would this be an antipattern for e2e testing)?

作为端到端测试的一部分,您需要注意设置初始应用程序状态,以及每个用例的状态(如果适用)。通过端到端测试,您需要测试所有应用程序行为,因此这里没有太多地方可以进行模拟。 运行 测试后,您可以销毁所有应用程序资源,服务清除数据库。我相信这是可选步骤,因为设置应用程序或用例状态地址 resource/database 准备。

最后,如果您没有合适的工具集和良好的数据组织策略,端到端测试可能会充满挑战,尤其是随着时间的推移,您最终会针对中小型应用程序进行数百个用例测试。除此之外,您还需要端到端测试工具,它可以与以任何语言编写的多堆栈应用程序一起工作(java,javascript golang,随便你怎么说),并支持任何平台的自动化,包括 localbox,docker, kubernetess, 无服务器云。

以下是一些测试读物:

我们的测试是这样进行的。这种程度的努力在许多组织中可能不可行,但我确实认为它非常有效。相对于您最初的问题,我认为,在可能的情况下,使用真实的东西而不是模拟,例如,使用下面概述的真实数据库。

基本架构

  • Sql 服务器数据库
  • C# 中间件
  • Angular前端

完整 CI/CD 到位。 CI 运行 个在 docker 个容器中。整个测试策略(UAT 测试除外)每次推送 运行s。

中间件

  • 单元测试:
    • Class 水平测试。
    • 数据库连接指向内存中实现。
    • Dependent 类 被 NSubstitute 模拟。
  • 集成测试:
    • 我们的基础服务库有一个允许模拟的测试配置基础设施:
      • 其他外部 http 服务。
      • 内部服务。
      • 身份验证对象(用户、令牌等)。
      • 通过依赖注入接口的任何其他实体。
    • 数据库
      • 测试 运行 的 docker 容器引用另一个包含 Sql 服务器的 linux 容器(mcr.microsoft。com/mssql/server :2017-最新-ubuntu).
      • 因此,针对真实数据库的测试运行。
      • 该服务拥有一个脚本列表,无论它在哪里启动(不仅在 CI 中),它都会根据需要执行这些脚本。因此,在每个 CI 运行 期间,它会播放整个历史记录。然而,这非常快,因为数据库开始时是空的。
        • 这个测试策略的漏洞是性能测试。
      • 测试配置初始化将连接字符串设置为此本地数据库。
    • 真正的服务启动,配置测试。

前端

标准,angular 单元/组件测试 运行 通过 angular 工具 + 业力。

端到端

  • Cypress 是使用的框架。
  • 中间件和前端都启动了。此处启动的中间件配置方式与上述中间件测试下的集成测试相同(相同的入口点)。
  • 有一些对外部服务的调用是在我们的直接控制之外发生的。我们使用 cypress hook 来防止发生这些调用。

UAT 测试

产品所有者在发布前进行的手动测试。