# Beginner's guide to writing end-to-end tests > 原文:[https://docs.gitlab.com/ee/development/testing_guide/end_to_end/beginners_guide.html](https://docs.gitlab.com/ee/development/testing_guide/end_to_end/beginners_guide.html) * [Before you write a test](#before-you-write-a-test) * [Determine if end-to-end tests are needed](#determine-if-end-to-end-tests-are-needed) * [Identify the DevOps stage](#identify-the-devops-stage) * [Create a skeleton test](#create-a-skeleton-test) * [The outer `context` block](#the-outer-context-block) * [The outer `RSpec.describe` block](#the-outer-rspecdescribe-block) * [The `describe` block](#the-describe-block) * [The `it` blocks (examples)](#the-it-blocks-examples) * [Write the test](#write-the-test) * [De-duplicate your code](#de-duplicate-your-code) * [Test setup using resources and page objects](#test-setup-using-resources-and-page-objects) * [Write the page object](#write-the-page-object) * [Run the spec](#run-the-spec) # Beginner’s guide to writing end-to-end tests[](#beginners-guide-to-writing-end-to-end-tests "Permalink") 在本教程中,您将学习如何为[GitLab 社区版](https://about.gitlab.com/install/?version=ce)和[GitLab 企业版](https://about.gitlab.com/install/)创建端到端( *e2e* )测试. 在本教程结束时,您将能够: * 确定是否需要端到端测试. * Understand the directory structure within `qa/`. * 编写一个基本的端到端测试,以验证登录功能. * 开发任何缺少的[页面对象](page_objects.html)库. ## Before you write a test[](#before-you-write-a-test "Permalink") 在编写测试之前,必须将您的[GitLab 开发套件(GDK)](https://gitlab.com/gitlab-org/gitlab-development-kit)配置为运行规范. 端到端测试: * 包含在`qa/`目录中. * 应该是独立和[幂等的](https://en.wikipedia.org/wiki/Idempotence#Computer_science_meaning) . * 临时创建[资源](resources.html) (例如项目,问题,用户). * Test the UI and API interfaces, and use the API to efficiently set up the UI tests. **提示:**有关更多信息,请参阅[端到端测试最佳实践](best_practices.html) . ## Determine if end-to-end tests are needed[](#determine-if-end-to-end-tests-are-needed "Permalink") 在编写端到端测试之前,请为[GitLab 社区版](https://gitlab-org.gitlab.io/gitlab-foss/coverage-ruby/#_AllFiles)和[GitLab 企业版](https://gitlab-org.gitlab.io/gitlab/coverage-ruby/#_AllFiles)项目检查特定功能的代码覆盖率. 在单元,功能或集成级别上是否存在足够的测试范围? 如果回答*是肯定的* ,那么你*就*需要一个终端到终端的测试. 有关 GitLab 中每个级别的测试分布的信息,请参见[测试级别](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/development/testing_guide/testing_levels.md) . * 请参阅[如何以正确的级别进行测试?](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/development/testing_guide/testing_levels.md#how-to-test-at-the-correct-level) " [测试级别"](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/development/testing_guide/testing_levels.md)文档的"部分". * 查看功能更改的频率. 如果较低级别的测试中已经包含了稳定的特性,那么这些特性不会经常更改,那么端到端测试可能就不值得考虑. * 最后,与参与实现功能和较低级别测试的开发人员讨论建议的测试. **注意:**检查[GitLab 社区版](https://gitlab-org.gitlab.io/gitlab-foss/coverage-ruby/#_AllFiles)和[GitLab 企业版](https://gitlab-org.gitlab.io/gitlab/coverage-ruby/#_AllFiles)覆盖率项目,以检查是否为此功能编写了以前的测试. 为了分析代码覆盖率,您必须了解哪些应用程序文件实现了特定功能.**注意:**在本教程中,我们将编写一个登录端到端测试,即使它已经被较低级别的测试所覆盖,因为这是大多数端到端流的第一步,并且最容易理解. ## Identify the DevOps stage[](#identify-the-devops-stage "Permalink") GitLab QA 端到端测试是由[DevOps 生命周期](https://gitlab.com/gitlab-org/gitlab-foss/tree/master/qa/qa/specs/features/browser_ui)的不同[阶段](https://gitlab.com/gitlab-org/gitlab-foss/tree/master/qa/qa/specs/features/browser_ui)组织的. 确定应按[阶段](https://about.gitlab.com/handbook/product/product-categories/#devops-stages)放置测试的位置,确定该测试属于哪个功能,然后将其放置在该阶段下的子目录中. [![DevOps lifecycle by stages](img/31396caea61831939862213abb8dd10c.png)](img/gl-devops-lifecycle-by-stage-numbers_V12_10.png) **注意:**如果该测试仅是企业版,则将在`features/ee`目录中创建该测试,但遵循相同的 DevOps 生命周期格式. ## Create a skeleton test[](#create-a-skeleton-test "Permalink") 在本教程的第一部分中,我们将测试由 Manage 阶段拥有的登录名. 在`qa/specs/features/browser_ui/1_manage/login` ,创建文件`basic_login_spec.rb` . ### The outer `context` block[](#the-outer-context-block "Permalink") 参见[`RSpec.describe`外部块](#the-outer-rspecdescribe-block) **弃用声明:**遵循 RSpec 4.0 规范在`13.2`中[弃用](https://gitlab.com/gitlab-org/quality/team-tasks/-/issues/550)了外部`context` . 请改用`RSpec.describe` . ### The outer `RSpec.describe` block[](#the-outer-rspecdescribe-block "Permalink") 规格具有外部`RSpec.describe`指示 DevOps 阶段. ``` # frozen_string_literal: true module QA RSpec.describe 'Manage' do end end ``` ### The `describe` block[](#the-describe-block "Permalink") 在我们的外部`RSpec.describe`内部,描述要测试的功能. 在这种情况下,请`Login` . ``` # frozen_string_literal: true module QA RSpec.describe 'Manage' do describe 'Login' do end end end ``` ### The `it` blocks (examples)[](#the-it-blocks-examples "Permalink") 每个测试套件包含至少一个`it`阻断(实施例). 一个好方法,开始写终端到终端的测试是编写测试用例描述为`it`块: ``` module QA RSpec.describe 'Manage' do describe 'Login' do it 'can login' do end it 'can logout' do end end end end ``` ## Write the test[](#write-the-test "Permalink") 一个重要的问题是"我们要测试什么?" 更重要的是,"我们如何测试?" 首先登录. ``` # frozen_string_literal: true module QA RSpec.describe 'Manage' do describe 'Login' do it 'can login' do Flow::Login.sign_in end it 'can logout' do Flow::Login.sign_in end end end end ``` [运行规范后](#run-the-spec) ,我们的测试应登录并结束; 那么我们应该回答"我们要测试什么?"这个问题. ``` # frozen_string_literal: true module QA RSpec.describe 'Manage' do describe 'Login' do it 'can login' do Flow::Login.sign_in Page::Main::Menu.perform do |menu| expect(menu).to be_signed_in end end it 'can logout' do Flow::Login.sign_in Page::Main::Menu.perform do |menu| menu.sign_out expect(menu).not_to be_signed_in end end end end end ``` **我们要测试什么?** 1. 我们可以登录吗? 2. 我们可以注销吗? **我们如何测试?** 1. 检查用户头像是否出现在顶部导航中. 2. 检查用户头像*是否未*出现在顶部导航中. **注意:**在幕后, `be_signed_in`是一个[谓词匹配器](https://relishapp.com/rspec/rspec-expectations/v/3-8/docs/built-in-matchers/predicate-matchers) ,可[实现对用户头像的检查](https://gitlab.com/gitlab-org/gitlab/-/blob/master/qa/qa/page/main/menu.rb#L74) . ## De-duplicate your code[](#de-duplicate-your-code "Permalink") 将测试重构为使用`before`块进行测试设置,因为它复制了对`sign_in`的调用. ``` # frozen_string_literal: true module QA RSpec.describe 'Manage' do describe 'Login' do before do Flow::Login.sign_in end it 'can login' do Page::Main::Menu.perform do |menu| expect(menu).to be_signed_in end end it 'can logout' do Page::Main::Menu.perform do |menu| menu.sign_out expect(menu).not_to be_signed_in end end end end end ``` `before`块本质上是一个`before(:each)`并且在每个示例之前运行,确保我们现在在每个测试的开始处登录. ## Test setup using resources and page objects[](#test-setup-using-resources-and-page-objects "Permalink") 接下来,让我们测试登录以外的其他功能. 让我们测试"计划"阶段拥有的"问题",因此在`qa/specs/features/browser_ui/3_create/issues` [创建一个](#identify-the-devops-stage)名为`issues_spec.rb` . ``` # frozen_string_literal: true module QA RSpec.describe 'Plan' do describe 'Issues' do let(:issue) do Resource::Issue.fabricate_via_api! do |issue| issue.title = 'My issue' issue.description = 'This is an issue specific to this test' end end before do Flow::Login.sign_in issue.visit! end it 'can close an issue' do Page::Project::Issue::Show.perform do |show| show.click_close_issue_button expect(show).to be_closed end end end end end ``` 请注意以下要点: * 在我们的示例开始时,我们将在`page/issue/show.rb` [页面](page_objects.html) . * 我们的测试仅在需要时制造需要的东西. * 该问题是通过 API 伪造的,以节省时间. * GitLab 更喜欢`let()`不是实例变量. 查看[最佳做法](../best_practices.html#let-variables) . * `be_closed`尚未在`page/project/issue/show.rb`中实现,但将在下一步中实现. 该问题被伪装成[Resource](resources.html) ,它是您可以通过 UI 或 API 创建的 GitLab 实体. 其他示例包括: * A [Merge Request](https://gitlab.com/gitlab-org/gitlab/-/blob/master/qa/qa/resource/merge_request.rb). * A [User](https://gitlab.com/gitlab-org/gitlab/-/blob/master/qa/qa/resource/user.rb). * A [Project](https://gitlab.com/gitlab-org/gitlab/-/blob/master/qa/qa/resource/project.rb). * A [Group](https://gitlab.com/gitlab-org/gitlab/-/blob/master/qa/qa/resource/group.rb). ## Write the page object[](#write-the-page-object "Permalink") [Page Object](page_objects.html)是我们套件中的一个类,代表 GitLab 中的一个页面. **登录**页面就是一个例子. 由于我们的" **问题显示"**页面的页面对象已经存在,请添加`closed?` 方法. ``` module Page::Project::Issue class Show view 'app/views/projects/issues/show.html.haml' do element :closed_status_box end def closed? has_element?(:closed_status_box) end end end ``` 接下来,在视图中定义元素`closed_status_box` ,以便页面对象可以看到它. ``` -#=> app/views/projects/issues/show.html.haml .issuable-status-box.status-box.status-box-issue-closed{ ..., data: { qa_selector: 'closed_status_box' } } ``` ## Run the spec[](#run-the-spec "Permalink") 在运行规范之前,请确认: * GDK 已安装. * GDK 在本地 3000 端口上运行. * 尚未应用其他[RSpec 元数据标签](rspec_metadata_tests.html) . * 您的工作目录是 GDK GitLab 安装中的`qa/` . 要运行该规范,请运行以下命令: ``` bundle exec bin/qa Test::Instance::All http://localhost:3000 -- ``` Where `` is: * 运行"登录"示例时,请输入`qa/specs/features/browser_ui/1_manage/login/login_spec.rb` . * 运行"问题"示例时,请执行`qa/specs/features/browser_ui/2_plan/issues/issue_spec.rb` .