本文主要介紹了在編寫 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
每個塊的嵌套都會起一個新的環境,每個環境的實體可能相同,需要添加環境前綴以將他們區分開