- Beginner’s guide to writing end-to-end tests
- Beginner’s guide to writing end-to-end tests
Beginner’s guide to writing end-to-end tests
原文:https://docs.gitlab.com/ee/development/testing_guide/end_to_end/beginners_guide.html
- Before you write a test
- Determine if end-to-end tests are needed
- Identify the DevOps stage
- Create a skeleton test
- Write the test
- De-duplicate your code
- Test setup using resources and page objects
- Write the page object
- Run the spec
Beginner’s guide to writing end-to-end tests
在本教程中,您将学习如何为GitLab 社区版和GitLab 企业版创建端到端( e2e )测试.
在本教程结束时,您将能够:
- 确定是否需要端到端测试.
- Understand the directory structure within
qa/
. - 编写一个基本的端到端测试,以验证登录功能.
- 开发任何缺少的页面对象库.
Before you write a test
在编写测试之前,必须将您的GitLab 开发套件(GDK)配置为运行规范. 端到端测试:
- 包含在
qa/
目录中. - 应该是独立和幂等的 .
- 临时创建资源 (例如项目,问题,用户).
- Test the UI and API interfaces, and use the API to efficiently set up the UI tests.
提示:有关更多信息,请参阅端到端测试最佳实践 .
Determine if end-to-end tests are needed
在编写端到端测试之前,请为GitLab 社区版和GitLab 企业版项目检查特定功能的代码覆盖率. 在单元,功能或集成级别上是否存在足够的测试范围? 如果回答是肯定的 ,那么你就需要一个终端到终端的测试.
有关 GitLab 中每个级别的测试分布的信息,请参见测试级别 .
- 请参阅如何以正确的级别进行测试? “ 测试级别”文档的”部分”.
- 查看功能更改的频率. 如果较低级别的测试中已经包含了稳定的特性,那么这些特性不会经常更改,那么端到端测试可能就不值得考虑.
- 最后,与参与实现功能和较低级别测试的开发人员讨论建议的测试.
注意:检查GitLab 社区版和GitLab 企业版覆盖率项目,以检查是否为此功能编写了以前的测试. 为了分析代码覆盖率,您必须了解哪些应用程序文件实现了特定功能.注意:在本教程中,我们将编写一个登录端到端测试,即使它已经被较低级别的测试所覆盖,因为这是大多数端到端流的第一步,并且最容易理解.
Identify the DevOps stage
GitLab QA 端到端测试是由DevOps 生命周期的不同阶段组织的. 确定应按阶段放置测试的位置,确定该测试属于哪个功能,然后将其放置在该阶段下的子目录中.
注意:如果该测试仅是企业版,则将在features/ee
目录中创建该测试,但遵循相同的 DevOps 生命周期格式.
Create a skeleton test
在本教程的第一部分中,我们将测试由 Manage 阶段拥有的登录名. 在qa/specs/features/browser_ui/1_manage/login
,创建文件basic_login_spec.rb
.
The outer context
block
弃用声明:遵循 RSpec 4.0 规范在13.2
中弃用了外部context
. 请改用RSpec.describe
.
The outer RSpec.describe
block
规格具有外部RSpec.describe
指示 DevOps 阶段.
# frozen_string_literal: true
module QA
RSpec.describe 'Manage' do
end
end
The describe
block
在我们的外部RSpec.describe
内部,描述要测试的功能. 在这种情况下,请Login
.
# frozen_string_literal: true
module QA
RSpec.describe 'Manage' do
describe 'Login' do
end
end
end
The it
blocks (examples)
每个测试套件包含至少一个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
一个重要的问题是”我们要测试什么?” 更重要的是,”我们如何测试?”
首先登录.
# 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
运行规范后 ,我们的测试应登录并结束; 那么我们应该回答”我们要测试什么?”这个问题.
# 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
我们要测试什么?
- 我们可以登录吗?
- 我们可以注销吗?
我们如何测试?
- 检查用户头像是否出现在顶部导航中.
- 检查用户头像是否未出现在顶部导航中.
注意:在幕后, be_signed_in
是一个谓词匹配器 ,可实现对用户头像的检查 .
De-duplicate your code
将测试重构为使用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
接下来,让我们测试登录以外的其他功能. 让我们测试”计划”阶段拥有的”问题”,因此在qa/specs/features/browser_ui/3_create/issues
创建一个名为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
页面 . - 我们的测试仅在需要时制造需要的东西.
- 该问题是通过 API 伪造的,以节省时间.
- GitLab 更喜欢
let()
不是实例变量. 查看最佳做法 . be_closed
尚未在page/project/issue/show.rb
中实现,但将在下一步中实现.
该问题被伪装成Resource ,它是您可以通过 UI 或 API 创建的 GitLab 实体. 其他示例包括:
- A Merge Request.
- A User.
- A Project.
- A Group.
Write the page object
Page Object是我们套件中的一个类,代表 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
在运行规范之前,请确认:
- GDK 已安装.
- GDK 在本地 3000 端口上运行.
- 尚未应用其他RSpec 元数据标签 .
- 您的工作目录是 GDK GitLab 安装中的
qa/
.
要运行该规范,请运行以下命令:
bundle exec bin/qa Test::Instance::All http://localhost:3000 -- <test_file>
Where <test_file>
is:
- 运行”登录”示例时,请输入
qa/specs/features/browser_ui/1_manage/login/login_spec.rb
. - 运行”问题”示例时,请执行
qa/specs/features/browser_ui/2_plan/issues/issue_spec.rb
.