本文主要介绍了在编写 E2E 测试代码时,需要遵循的规范和最佳实践。
如果你对 E2E 测试还一无所知,可以先来读一下 Gitlab E2E 测试的一些常识。
Upstream 的代码大部分类已经实现了版本重载功能,可以实现 CE -> EE -> JH 版本重载的功能。
重载总共有两步:
prepend_mod_with
功能:
# gdk/gitlab/qa/qa/runtime/env.rb
module QA
module Runtime
module Env
# ...
end
end
end
QA::Runtime::Env.prepend_mod_with('Runtime::Env', namespace: QA)
# gdk/gitlab/jh/qa/qa/jh/runtime/env.rb
module QA
module JH
module Runtime
module Env
extend ActiveSupport::Concern
class_methods do
def class_method
# ...
end
end
def instance_method
# ...
end
end
end
end
end
细心会发现重载方法其实总共有三个:
prepend_mod_with
: 重载组件的实例方法(Class.new.xxx),方法优先级比 Upstream 更高。该方法也可以通过钩子重载类方法,因此我们统一只使用这个方法。extend_mod_with
: 重载组件的类方法(静态方法)(Class.xxx),方法优先级比 Upstream 更高include_mod_with
: 重载组件的实例方法(Class.new.xxx),方法优先级比 Upstream 更低,因此用这个方法的场景只有极狐新增方法,且希望将来 Upstream 出现同名方法时优先 Upstream 的方法qa/qa/jh/
目录下(参照的是 GitLab 主项目的重载方案) QA::Page::Group::Menu -> QA::JH::Page::Group::Menu
QA::Runtime::Env -> QA::JH::Runtime::Env
prepend_mod_with
是用的最多的重载方法,因为他支持覆写 Upstream 已有的方法和给 Upstream 组件添加新的方法。这里为了后期好维护,对于覆写需要添加特殊注释:
# gdk/gitlab/jh/qa/qa/jh/runtime/env.rb
module QA
module JH
module Runtime
module Env
# @override :upstream_method
def upstream_method
# ...
end
def jihu_new_method
# ...
end
end
end
end
end
极狐专属功能也需要添加 E2E 测试,需要写自己的 QA 组件,写这些组件主要注意下面几点:
qa/qa/
目录下(参照的是 GitLab 主项目的重载方案)这两个错误很常见,但是调试具体原因也是有方法的,首先可以给 gdk/gitlab/qa/qa.rb
最底部加个断点(因为此处是刚加载完所有组件的地方,刚好用于排查常量和方法问题):
# gdk/gitlab/qa/qa.rb
require 'pry'
module QA
# ...
binding.pry
end
然后运行一个测试,到达断点处,尝试运行出错常量和方法复现错误,然后可以按下面方案处理:
Zeitwerk
库要求(可以参考已有常量),然后尝试将相对常量换成绝对常量(因为复杂嵌套下,可能找错):
Menu -> ::QA::Page::Group::Menu
Env -> ::QA::Runtime::Env
QA::Runtime::Env
用重载方式添加的 jh_env
方法没找到:
QA::JH::Runtime::Env.instance_methods.include?('jh_env')
语句需要没有报错且返回 true
。QA::Runtime::Env.instance_methods.include?('jh_env')
语句需要没有报错且返回 true
。如果重载的是类方法,需要换成 QA::JH::Runtime::Env.methods.include?('jh_env')
prepend_mod_with
和 extend_mod_with
用错这类硬编码实际上只需要将硬编码部分拆取一个新的私有方法,然后极狐对这个私有方法进行覆盖即可,以下是一个例子:
Upstream 的待处理硬编码模块:
module QA
module M1
def execute
doing_thing_before
doing_thing_with_hardcode('upstream_hardcode')
doing_thing_after
end
end
end
处理后的示例:
# Upstream
module QA
module M1
def execute
doing_thing_before
doing_thing_with_hardcode(some_data)
doing_thing_after
end
private
def some_data
'upstream_hardcode'
end
end
end
# JH
module QA
module JH
module M1
private
# @override :some_data
def some_data
'jh_hardcode'
end
end
end
end
比如一个硬编码问题:
RSpec.describe 'Fulfillment' do
let(:user) { 'GitLab QA' }
let(:company) { 'QA User' }
let(:user_count) { 10_000 }
end
对于这个问题,因为测试用例都是 Block 环境,没有实体类/模块,因此无法直接抽取方法来覆盖。当前需要抽取一个 Data 模块出来实现, 具体抽取逻辑请参考这个 Upstream MR: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/103608
抽取 Data 模块完成之后,然后就只要在极狐这边重载这个 Data 模块即可解决硬编码码问题。
对于抽取 Data 模块规范,请遵守:
qa/qa/support/data/#{测试用例文件名}.rb
def #{文件名}_#{当前环境}_实体名
:
describe
, context
, it
每个块的嵌套都会起一个新的环境,每个环境的实体可能相同,需要添加环境前缀以将他们区分开