<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # Testing best practices > 原文:[https://docs.gitlab.com/ee/development/testing_guide/best_practices.html](https://docs.gitlab.com/ee/development/testing_guide/best_practices.html) * [Test Design](#test-design) * [Test speed](#test-speed) * [RSpec](#rspec) * [General guidelines](#general-guidelines) * [Coverage](#coverage) * [System / Feature tests](#system--feature-tests) * [Debugging Capybara](#debugging-capybara) * [Live debug](#live-debug) * [Run `:js` spec in a visible browser](#run-js-spec-in-a-visible-browser) * [Screenshots](#screenshots) * [Fast unit tests](#fast-unit-tests) * [`let` variables](#let-variables) * [Common test setup](#common-test-setup) * [Time-sensitive tests](#time-sensitive-tests) * [Feature flags in tests](#feature-flags-in-tests) * [`stub_feature_flags` vs `Feature.enable*`](#stub_feature_flags-vs-featureenable) * [Stubbing gate](#stubbing-gate) * [Pristine test environments](#pristine-test-environments) * [SQL database](#sql-database) * [Redis](#redis) * [Background jobs / Sidekiq](#background-jobs--sidekiq) * [DNS](#dns) * [Filesystem](#filesystem) * [Persistent in-memory application state](#persistent-in-memory-application-state) * [Table-based / Parameterized tests](#table-based--parameterized-tests) * [Prometheus tests](#prometheus-tests) * [Matchers](#matchers) * [`be_like_time`](#be_like_time) * [`have_gitlab_http_status`](#have_gitlab_http_status) * [Testing query performance](#testing-query-performance) * [QueryRecorder](#queryrecorder) * [GitalyClient](#gitalyclient) * [Shared contexts](#shared-contexts) * [Shared examples](#shared-examples) * [Helpers](#helpers) * [Factories](#factories) * [Fixtures](#fixtures) * [Repositories](#repositories) * [Configuration](#configuration) * [Test environment logging](#test-environment-logging) # Testing best practices[](#testing-best-practices "Permalink") ## Test Design[](#test-design "Permalink") 在 manbetx 客戶端打不開的測試是頭等公民,而不是事后的想法. 在設計功能時,必須考慮測試的設計,這一點很重要. 在實現功能時,我們考慮以正確的方式開發正確的功能,這有助于我們將范圍縮小到可管理的水平. 在對功能進行測試時,我們必須考慮開發正確的測試,然后涵蓋測試可能失敗的*所有*重要方式,這可能很快將我們的范圍擴大到難以管理的水平. 測試啟發法可以幫助解決此問題. 它們簡明地解決了錯誤在我們的代碼中表現出來的許多常見方式. 在設計測試時,請花一些時間來回顧已知的測試啟發法,以告知我們的測試設計. 我們可以在" [測試工程"](https://about.gitlab.com/handbook/engineering/quality/test-engineering/#test-heuristics)部分的"手冊"中找到一些有用的啟發式方法. ## Test speed[](#test-speed "Permalink") GitLab has a massive test suite that, without [parallelization](ci.html#test-suite-parallelization-on-the-ci), can take hours to run. It’s important that we make an effort to write tests that are accurate and effective *以及* fast. 關于測試性能,需要牢記以下幾點: * `instance_double`和`spy`比`FactoryBot.build(...)`快 * `FactoryBot.build(...)`和`.build_stubbed`比`.create`更快. * 當`build` , `build_stubbed` , `attributes_for` , `spy`或`instance_double`可以使用時,不要`create`對象. 數據庫持久性很慢! * 除非*實際*需要測試有效,否則不要將功能標記為需要 JavaScript(通過 RSpec 中的`:js` ). 無頭瀏覽器測試很慢! ## RSpec[](#rspec "Permalink") 要運行 RSpec 測試: ``` # run test for a file bin/rspec spec/models/project_spec.rb # run test for the example on line 10 on that file bin/rspec spec/models/project_spec.rb:10 # run tests matching the example name has that string bin/rspec spec/models/project_spec.rb -e associations # run all tests, will take hours for GitLab codebase! bin/rspec ``` 使用[Guard](https://github.com/guard/guard)連續監視更改,并僅運行匹配的測試: ``` bundle exec guard ``` 一起使用 spring 和 guard 時,請改用`SPRING=1 bundle exec guard`來使用 spring. 使用[Factory Doctor](https://test-prof.evilmartians.io/#/factory_doctor.md)查找不必要的數據庫操作案例,這可能會導致測試緩慢. ``` # run test for path FDOC=1 bin/rspec spec/[path]/[to]/[spec].rb ``` ### General guidelines[](#general-guidelines "Permalink") * 使用單個頂級`RSpec.describe ClassName`塊. * 使用`.method`來描述類方法,并使用`#method`來描述實例方法. * 使用`context`測試分支邏輯. * 嘗試使測試的順序與類中的順序匹配. * 嘗試遵循[四階段測試](https://thoughtbot.com/blog/four-phase-test)模式,使用換行符分隔各個階段. * 使用`Gitlab.config.gitlab.host`而不是硬編碼`'localhost'` * 不要斷言序列生成的屬性的絕對值(請參見[Gotchas](../gotchas.html#do-not-assert-against-the-absolute-value-of-a-sequence-generated-attribute) ). * 避免使用`expect_any_instance_of`或`allow_any_instance_of` (見[陷阱](../gotchas.html#do-not-assert-against-the-absolute-value-of-a-sequence-generated-attribute) ). * 不要將`:each`參數提供給鉤子,因為它是默認值. * 在鉤子`before`和`after` ,最好將它的作用域設置為`:context`不是`:all` * 當使用作用在給定元素上的`execute_script` `evaluate_script("$('.js-foo').testSomething()")` (或`execute_script` )時,請事先使用 Capybara 匹配器(例如`find('.js-foo')` )以確保該元素實際存在. * 使用`focus: true`可以隔離要運行的部分規范. * 如果測試中有多個期望,請使用[`:aggregate_failures`](https://relishapp.com/rspec/rspec-core/docs/expectation-framework-integration/aggregating-failures) . * 對于[空的測試描述塊](https://github.com/rubocop-hq/rspec-style-guide#it-and-specify) ,如果測試是不言自明的,請使用`specify`而不是`it do` . * 當您需要一個實際上不存在的 ID / IID /訪問級別時,請使用`non_existing_record_id` / `non_existing_record_iid` / `non_existing_record_access_level` . 使用 123、1234 甚至 999 都很容易,因為在 CI 運行的情況下,這些 ID 實際上可能存在于數據庫中. ### Coverage[](#coverage "Permalink") [`simplecov`](https://github.com/colszowka/simplecov)用于生成代碼測試覆蓋率報告. 它們是在 CI 上自動生成的,但在本地運行測試時不會自動生成. 要在計算機上運行規格文件時生成部分報告,請設置`SIMPLECOV`環境變量: ``` SIMPLECOV=1 bundle exec rspec spec/models/repository_spec.rb ``` 覆蓋率報告會生成到應用程序根目錄下的`coverage`文件夾中,您可以在瀏覽器中打開這些報告,例如: ``` firefox coverage/index.html ``` 使用覆蓋率報告來確保您的測試覆蓋 100%的代碼. ### System / Feature tests[](#system--feature-tests "Permalink") **注意:**在編寫新的系統測試之前, [請考慮**不要**編寫一個](testing_levels.html#consider-not-writing-a-system-test) ! * Feature specs should be named `ROLE_ACTION_spec.rb`, such as `user_changes_password_spec.rb`. * 使用描述成功和失敗路徑的方案標題. * 避免方案標題未添加任何信息,例如"成功". * 避免場景標題重復功能標題. * Create only the necessary records in the database * 測試一條幸福的道路和一條不太幸福的道路,僅此而已 * 所有其他可能的路徑均應通過單元測試或集成測試進行測試 * 測試頁面上顯示的內容,而不是 ActiveRecord 模型的內部. 例如,如果您要驗證是否已創建記錄,請添加期望其記錄顯示在頁面上的期望,而不是`Model.count`增加一. * 可以查找 DOM 元素,但不要濫用它,因為它會使測試更加脆弱 #### Debugging Capybara[](#debugging-capybara "Permalink") 有時您可能需要通過觀察瀏覽器行為來調試 Capybara 測試. #### Live debug[](#live-debug "Permalink") 您可以使用規范中的`live_debug`方法暫停 Capybara 并在瀏覽器中查看網站. 當前頁面將在默認瀏覽器中自動打開. 您可能需要先登錄(當前用戶的憑據顯示在終端中). 要恢復測試運行,請按任意鍵. 例如: ``` $ bin/rspec spec/features/auto_deploy_spec.rb:34 Running via Spring preloader in process 8999 Run options: include {:locations=>{"./spec/features/auto_deploy_spec.rb"=>[34]}} Current example is paused for live debugging The current user credentials are: user2 / 12345678 Press any key to resume the execution of the example! Back to the example! . Finished in 34.51 seconds (files took 0.76702 seconds to load) 1 example, 0 failures ``` 注意: `live_debug`僅在啟用 JavaScript 的規范上起作用. #### Run `:js` spec in a visible browser[](#run-js-spec-in-a-visible-browser "Permalink") 使用`CHROME_HEADLESS=0`運行規范,例如: ``` CHROME_HEADLESS=0 bin/rspec some_spec.rb ``` 測試將很快進行,但這將使您對正在發生的事情有所了解. 對`CHROME_HEADLESS=0`使用`live_debug`暫停打開的瀏覽器,并且不會再次打開該頁面. 這可用于調試和檢查元素. 您還可以添加`byebug`或`binding.pry`暫停執行,并[步通過](../pry_debugging.html#stepping)測試. #### Screenshots[](#screenshots "Permalink") 我們使用`capybara-screenshot` gem 在失敗時自動截屏. 在 CI 中,您可以下載這些文件作為作業工件. 另外,您可以通過添加以下方法在測試中的任何時候手動獲取屏幕截圖. 請確保在不再需要它們時將其刪除! 有關更多信息,請參見[https://github.com/mattheworiordan/capybara-screenshot#manual-screenshots](https://github.com/mattheworiordan/capybara-screenshot#manual-screenshots) . 在`:js`規范中添加`screenshot_and_save_page`以截圖 Capybara 看到的內容,并保存頁面源代碼. 在`:js`規范中添加`screenshot_and_open_image`以截圖 Capybara 看到的內容,并自動打開圖像. 由此創建的 HTML 轉儲缺少 CSS. 這導致它們看起來與實際應用程序截然不同. 有一個添加 CSS 的[小技巧](https://gitlab.com/gitlab-org/gitlab-foss/snippets/1718469) ,可簡化調試過程. ### Fast unit tests[](#fast-unit-tests "Permalink") 某些類與 Rails 完全隔離,您應該能夠測試它們,而不會因 Rails 環境和 Bundler 的`:default`組的 gem 加載而增加開銷. 在這些情況下,您可以在測試文件中`require 'fast_spec_helper'`而不是`require 'spec_helper'` ,并且由于以下原因,測試應該運行得非常快: * 寶石加載被跳過 * Rails 應用啟動被跳過 * 跳過了 GitLab Shell 和 Gitaly 設置 * 測試存儲庫設置被跳過 `fast_spec_helper`還支持`lib/`目錄中的自動加載類. 這意味著只要您的類/模塊僅使用`lib/`目錄中的代碼,就無需顯式加載任何依賴項. `fast_spec_helper`還將加載所有 ActiveSupport 擴展,包括 Rails 環境中常用的核心擴展. 請注意,在某些情況下,當代碼使用 gems 或`lib/`沒有依賴項時,您可能仍必須使用`require_dependency`加載某些依賴項. 例如,如果要測試調用`Gitlab::UntrustedRegexp`類的代碼,該類在`Gitlab::UntrustedRegexp`使用`re2`庫,則應將`require_dependency 're2'`添加到需要`re2` gem 的庫文件中,以達到此要求明確,也可以將其添加到規范本身中,但最好使用前者. 加載使用`fast_spec_helper`測試大約需要一秒鐘,而不是常規`spec_helper`的 30+秒. ### `let` variables[](#let-variables "Permalink") GitLab 的 RSpec 套件廣泛使用`let` (以及嚴格的非延遲版本`let!` )變量來減少重復. 但是,有時這有時要以[清楚為代價](https://thoughtbot.com/blog/lets-not) ,因此我們需要為以后的使用設置一些準則: * `let!` 變量優于實例變量. `let`變量比`let!`可取`let!` 變量. 局部變量比`let`變量更可取. * 使用`let`可以減少整個規格文件中的重復項. * 不要使用`let`定義單個測試使用的變量; 在測試的`it`塊中將它們定義為局部變量. * 不要在頂層`describe`塊中定義只用于更深層嵌套`context`或`describe`塊的`let`變量. 使定義盡可能靠近使用位置. * 盡量避免將一個`let`變量的定義覆蓋另一個. * 不要定義只供另一個定義使用的`let`變量. 請改用輔助方法. * `let!` 變量應該只在需要與定義為了嚴格評估的情況下使用,否則`let`就足夠了. 請記住, `let`是惰性的,在被引用之前不會被評估. ### Common test setup[](#common-test-setup "Permalink") 在某些情況下,無需為每個示例再次創建相同的對象以進行測試. 例如,需要一個項目和該項目的訪客來測試同一項目上的問題,一個項目和一個用戶將對整個文件進行測試. 盡可能不要使用`before(:all)`或`before(:context)`實現此目的. 如果這樣做,您將需要手動清理數據,因為這些掛鉤在數據庫事務外部運行. 相反,這可以通過使用來實現[`let_it_be`](https://test-prof.evilmartians.io/#/let_it_be)變量和[`before_all`](https://test-prof.evilmartians.io/#/before_all)鉤從[`test-prof`的寶石](https://rubygems.org/gems/test-prof) . ``` let_it_be(:project) { create(:project) } let_it_be(:user) { create(:user) } before_all do project.add_guest(user) end ``` 這將僅為此上下文創建一個`Project` , `User`和`ProjectMember` . `let_it_be`和`before_all`在嵌套上下文中也可用. 使用事務回滾自動處理上下文后進行清理. Note that if you modify an object defined inside a `let_it_be` block, then you will need to reload the object as needed, or specify the `reload` option to reload for every example. ``` let_it_be(:project, reload: true) { create(:project) } ``` 您還可以指定`refind`選項以完全加載新對象. ``` let_it_be(:project, refind: true) { create(:project) } ``` ### Time-sensitive tests[](#time-sensitive-tests "Permalink") 在基于 Ruby 的測試中可以使用[Timecop](https://github.com/travisjeffery/timecop)來驗證對時間敏感的事物. 任何鍛煉或驗證時間敏感的測試都應使用 Timecop 來防止瞬態測試失敗. Example: ``` it 'is overdue' do issue = build(:issue, due_date: Date.tomorrow) Timecop.freeze(3.days.from_now) do expect(issue).to be_overdue end end ``` ### Feature flags in tests[](#feature-flags-in-tests "Permalink") 在基于 Ruby 的測試中,默認情況下所有功能標志都已啟用. 要在測試中禁用功能標記,請使用`stub_feature_flags`幫助器. 例如,要在測試中全局禁用`ci_live_trace`功能標志: ``` stub_feature_flags(ci_live_trace: false) Feature.enabled?(:ci_live_trace) # => false ``` 如果您希望設置一個僅對某些角色而不對其他角色啟用功能標志的測試,則可以在傳遞給助手的選項中指定此功能. 例如,要為特定項目啟用`ci_live_trace`功能標記: ``` project1, project2 = build_list(:project, 2) # Feature will only be enabled for project1 stub_feature_flags(ci_live_trace: project1) Feature.enabled?(:ci_live_trace) # => false Feature.enabled?(:ci_live_trace, project1) # => true Feature.enabled?(:ci_live_trace, project2) # => false ``` 這代表了 FlipperGate 的實際行為: 1. 您可以啟用要啟用的指定角色的替代 2. 您可以禁用(刪除)指定角色的替代,并還原為默認狀態 3. 無法建模您明確禁用指定的參與者 ``` Feature.enable(:my_feature) Feature.disable(:my_feature, project1) Feature.enabled?(:my_feature) # => true Feature.enabled?(:my_feature, project1) # => true ``` ``` Feature.disable(:my_feature2) Feature.enable(:my_feature2, project1) Feature.enabled?(:my_feature2) # => false Feature.enabled?(:my_feature2, project1) # => true ``` #### `stub_feature_flags` vs `Feature.enable*`[](#stub_feature_flags-vs-featureenable "Permalink") 最好使用`stub_feature_flags`在測試環境中啟用功能標志. 該方法為簡單的用例提供了一個簡單且描述良好的界面. 但是,在某些情況下,需要測試更復雜的行為,例如功能標志百分比展示. 這可以使用`.enable_percentage_of_time`和`.enable_percentage_of_actors`來實現 ``` # Good: feature needs to be explicitly disabled, as it is enabled by default if not defined stub_feature_flags(my_feature: false) stub_feature_flags(my_feature: true) stub_feature_flags(my_feature: project) stub_feature_flags(my_feature: [project, project2]) # Bad Feature.enable(:my_feature_2) # Good: enable my_feature for 50% of time Feature.enable_percentage_of_time(:my_feature_3, 50) # Good: enable my_feature for 50% of actors/gates/things Feature.enable_percentage_of_actors(:my_feature_4, 50) ``` 具有定義狀態的每個功能標志將在測試執行時間內保留: ``` Feature.persisted_names.include?('my_feature') => true Feature.persisted_names.include?('my_feature_2') => true Feature.persisted_names.include?('my_feature_3') => true Feature.persisted_names.include?('my_feature_4') => true ``` #### Stubbing gate[](#stubbing-gate "Permalink") 要求將作為參數傳遞給`Feature.enabled?` 和`Feature.disabled?` 是包含`FeatureGate`的對象. 在規范中,您可以使用`stub_feature_flag_gate`方法,該方法可讓您快速使用自定義門: ``` gate = stub_feature_flag_gate('CustomActor') stub_feature_flags(ci_live_trace: gate) Feature.enabled?(:ci_live_trace) # => false Feature.enabled?(:ci_live_trace, gate) # => true ``` ### Pristine test environments[](#pristine-test-environments "Permalink") 單個 GitLab 測試執行的代碼可以訪問和修改許多數據項. 無需在測試運行之前進行仔細的準備,然后再進行清理,則測試可以更改數據,從而影響后續測試的行為. 應不惜一切代價避免這種情況! 幸運的是,現有的測試框架已經可以處理大多數情況. 當測試環境確實受到污染時,常見的結果就是[不穩定的測試](flaky_tests.html) . 污染通常表現為順序依賴性:運行規格 A,然后運行規格 B 會可靠地失敗,但是運行規格 B,然后運行規格 A 將可靠地成功. 在這些情況下,可以使用`rspec --bisect` (或規格文件的手動成對二`rspec --bisect` )來確定哪個規格有問題. 要解決此問題,需要對測試套件如何確保原始環境有一些了解. 繼續閱讀以發現有關每個數據存儲的更多信息! #### SQL database[](#sql-database "Permalink") 這是由`database_cleaner` gem 為我們管理的. 每個規范都包含在一個事務中,一旦測試完成,該事務將回滾. 某些規范將在完成后針對每個表發出`DELETE FROM`查詢; 這樣可以從多個數據庫連接中查看創建的行,這對于在瀏覽器中運行的規范或遷移規范等非常重要. 使用這些策略而不是眾所周知的`TRUNCATE TABLES`方法的結果是,主鍵和其他序列**不會**在整個規范中重置. 因此,如果您在規范 A 中創建一個項目,然后在規范 B 中創建一個項目,則第一個將具有`id=1` ,而第二個將具有`id=2` . 這意味著規范**永遠**不應依賴 ID 或任何其他序列生成的列的值. 為避免意外沖突,規范還應避免手動指定此類列中的任何值. 而是將它們保留為未指定狀態,并在創建行后查找值. #### Redis[](#redis "Permalink") GitLab 在 Redis 中存儲了兩個主要的數據類別:緩存項和 Sidekiq 作業. 在大多數規范中,Rails 緩存實際上是一個內存存儲. 規格之間已替換了該代碼,因此對`Rails.cache.read`和`Rails.cache.write`調用是安全的. 但是,如果某個規范直接進行 Redis 調用,則應適當地使用`:clean_gitlab_redis_cache` , `:clean_gitlab_redis_shared_state`或`:clean_gitlab_redis_queues`特征對其進行標記. #### Background jobs / Sidekiq[](#background-jobs--sidekiq "Permalink") 默認情況下,Sidekiq 作業會排隊到作業數組中,并且不會進行處理. 如果測試將 Sidekiq 作業排入隊列并需要對其進行處理,則可以使用`:sidekiq_inline`特性. The `:sidekiq_might_not_need_inline` trait was added when [Sidekiq inline mode was changed to fake mode](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/15479) to all the tests that needed Sidekiq to actually process jobs. Tests with this trait should be either fixed to not rely on Sidekiq processing jobs, or their `:sidekiq_might_not_need_inline` trait should be updated to `:sidekiq_inline` if the processing of background jobs is needed/expected. **注意:** `perform_enqueued_jobs`的用法僅對測試延遲的郵件傳遞有用,因為我們的 Sidekiq 工作者不是從`ApplicationJob` / `ActiveJob::Base`繼承. #### DNS[](#dns "Permalink") DNS 請求在測試套件中普遍存在(截至[!22368](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/22368) ),因為 DNS 可能會導致問題,具體取決于開發人員的本地網絡. 在`spec/support/dns.rb`有可用的 RSpec 標簽,如果您需要繞過 DNS 存根,則可以將其應用于測試,例如: ``` it "really connects to Prometheus", :permit_dns do ``` 而且,如果需要更具體的控制,則可以在`spec/support/helpers/dns_helpers.rb`實現 DNS 阻止,并且可以在其他地方調用這些方法. #### Filesystem[](#filesystem "Permalink") 文件系統數據可以大致分為"存儲庫"和"其他所有內容". 存儲庫存儲在`tmp/tests/repositories` . 在測試運行開始之前和測試運行結束之后,將清空此目錄. 在規格之間不清空它,因此在過程的整個生命周期中,創建的存儲庫都在此目錄中累積. 刪除它們很昂貴,但是除非精心管理,否則可能會導致污染. 為避免這種情況,在測試套件中啟用了[哈希存儲](../../administration/repository_storage_types.html) . 這意味著將為存儲庫提供一個唯一的路徑,該路徑取決于其項目的 ID. 由于在規范之間未重置項目 ID,因此可以確保每個規范在磁盤上獲得自己的存儲庫,并防止在規范之間可見更改. 如果規范手動指定了項目 ID,或直接檢查`tmp/tests/repositories/`目錄的狀態,則它應該在運行之前和之后清理該目錄. 通常,應完全避免這些模式. 鏈接到數據庫對象的其他文件類別(例如上載)通常以相同的方式進行管理. 在規范中啟用了散列存儲后,它們將在 ID 確定的位置寫入磁盤,因此不會發生沖突. 一些規范通過將`:legacy_storage`特征傳遞給`projects`工廠來禁用哈希存儲. 執行此操作的規范絕**不能**覆蓋項目或其任何組的`path` . 默認路徑包含項目 ID,因此不會發生沖突. 但是,如果兩個規范創建具有相同路徑的`:legacy_storage`項目,則它們將使用磁盤上的相同存儲庫并導致測試環境污染. 其他文件必須由規范手動管理. 例如,如果運行創建`tmp/test-file.csv`文件的代碼,則規范必須確保在清理過程中刪除了該文件. #### Persistent in-memory application state[](#persistent-in-memory-application-state "Permalink") 給定`rspec`運行中的所有規范共享相同的 Ruby 進程,這意味著它們可以通過修改規范之間可訪問的 Ruby 對象相互影響. 實際上,這意味著全局變量和常量(包括 Ruby 類,模塊等). 全局變量通常不應修改. 如果絕對必要,則可以使用如下所示的塊來確保更改被回滾: ``` around(:each) do |example| old_value = $0 begin $0 = "new-value" example.run ensure $0 = old_value end end ``` 如果規范需要修改常量,則應使用`stub_const`幫助器以確保更改被回滾. 如果需要修改`ENV`常量的內容,則可以改用`stub_env`幫助器方法. 雖然大多數 Ruby **實例**不在規范之間共享,但**類**和**模塊**通常是共享的. 類和模塊實例變量,訪問器,類變量和其他有狀態習語應與全局變量一樣對待-除非必須修改,否則請勿對其進行修改! 特別是,最好使用期望值或依賴項注入以及存根,以避免進行修改. 如果沒有其他選擇,可以使用類似于上面的全局變量示例的`around`塊,但應盡可能避免這種情況. ### Table-based / Parameterized tests[](#table-based--parameterized-tests "Permalink") 這種測試風格用于執行一段具有廣泛輸入范圍的代碼. 通過一次指定測試用例,并在每個輸入和預期輸出表的旁邊,可以使您的測試更易于閱讀和緊湊. 我們使用[RSpec :: Parameterized](https://github.com/tomykaira/rspec-parameterized) gem. 一個簡短的示例,使用表語法并檢查 Ruby 相等性是否為一系列輸入,可能看起來像這樣: ``` describe "#==" do using RSpec::Parameterized::TableSyntax where(:a, :b, :result) do 1 | 1 | true 1 | 2 | false true | true | true true | false | false end with_them do it { expect(a == b).to eq(result) } it 'is isomorphic' do expect(b == a).to eq(result) end end end ``` **注意:**僅將簡單值用作`where`塊中的輸入. 使用 proc,有狀態對象,FactoryBot 創建的對象等可能導致[意外結果](https://github.com/tomykaira/rspec-parameterized/issues/8) . ### Prometheus tests[](#prometheus-tests "Permalink") 可以將 Prometheus 度量從一次測試運行保存到另一次測試. 為了確保在每個示例之前重置指標,請在 RSpec 測試中添加`:prometheus`標記. ### Matchers[](#matchers "Permalink") 應該創建自定義匹配器以闡明意圖和/或隱藏 RSpec 期望的復雜性. 它們應放在`spec/support/matchers/` . 如果匹配器僅適用于某種類型的規范(例如功能,請求等),則可以放在子文件夾中,但如果它們適用于多種類型的規范,則不應該放在子文件夾中. #### `be_like_time`[](#be_like_time "Permalink") 從數據庫返回的時間的精度可能與 Ruby 中的時間對象不同,因此在規格比較時我們需要靈活的容差. 我們可以使用`be_like_time`來比較時間在彼此之間一秒之內. Example: ``` expect(metrics.merged_at).to be_like_time(time) ``` #### `have_gitlab_http_status`[](#have_gitlab_http_status "Permalink") `have_gitlab_http_status`使用`have_http_status`而不是`have_http_status`和`have_http_status` `expect(response.status).to` `have_http_status` ,因為只要狀態不匹配,前者還可以顯示響應主體. 每當某些測試開始中斷時,這將非常有用,我們很想知道為什么不編輯源代碼并重新運行測試. 每當它顯示 500 內部服務器錯誤時,此功能特別有用. 在數字表示形式`206` `:no_content`命名為 HTTP 的狀態,如`:no_content` . 請參閱[支持的狀態代碼](https://github.com/rack/rack/blob/f2d2df4016a906beec755b63b4edfcc07b58ee05/lib/rack/utils.rb#L490)列表. Example: ``` expect(response).to have_gitlab_http_status(:ok) ``` ### Testing query performance[](#testing-query-performance "Permalink") 測試查詢性能使我們能夠: * 斷言代碼塊中不存在 N + 1 個問題. * 確保代碼塊中的查詢數量不會被忽略. #### QueryRecorder[](#queryrecorder "Permalink") `QueryRecorder`允許分析和測試在給定代碼塊中執行的數據庫查詢的數量. 有關更多詳細信息,請參見[`QueryRecorder`](../query_recorder.html)部分. #### GitalyClient[](#gitalyclient "Permalink") `Gitlab::GitalyClient.get_request_count` allows tests of the number of Gitaly queries made by a given block of code: 有關更多詳細信息,請參見[`Gitaly Request Counts`](../gitaly.html#request-counts)部分. ### Shared contexts[](#shared-contexts "Permalink") 可以內聯聲明僅在一個規范文件中使用的共享上下文. 一個以上規范文件使用的任何共享上下文: * 應該放在`spec/support/shared_contexts/` . * 如果它們僅適用于某種類型的規范(例如功能,請求等),則可以放在子文件夾中,但如果它們適用于多種類型的規范,則不應放在子文件夾中. 每個文件應僅包含一個上下文并具有描述性名稱,例如`spec/support/shared_contexts/controllers/githubish_import_controller_shared_context.rb` . ### Shared examples[](#shared-examples "Permalink") 可以內聯聲明僅在一個規范文件中使用的共享示例. 多個規范文件使用的任何共享示例: * 應該放在`spec/support/shared_examples/` . * 如果它們僅適用于某種類型的規范(例如功能,請求等),則可以放在子文件夾中,但如果它們適用于多種類型的規范,則不應放在子文件夾中. 每個文件應僅包含一個上下文并具有描述性名稱,例如`spec/support/shared_examples/controllers/githubish_import_controller_shared_example.rb` . ### Helpers[](#helpers "Permalink") 幫助程序通常是提供一些隱藏特定 RSpec 示例復雜性的方法的模塊. 如果不希望與其他規范共享,則可以在 RSpec 文件中定義幫助程序. 否則,應將它們放在`spec/support/helpers/` . 如果助手僅適用于某種類型的規范(例如功能,請求等),則可以放在子文件夾中,但如果它們適用于多種類型的規范,則不應放在子文件夾中. 助手應遵循 Rails 的命名/命名空間約定. 例如`spec/support/helpers/cycle_analytics_helpers.rb`應該定義: ``` module Spec module Support module Helpers module CycleAnalyticsHelpers def create_commit_referencing_issue(issue, branch_name: random_git_name) project.repository.add_branch(user, branch_name, 'master') create_commit("Commit for ##{issue.iid}", issue.project, user, branch_name) end end end end end ``` 助手不應更改 RSpec 配置. 例如,上述幫助器模塊不應包括: ``` RSpec.configure do |config| config.include Spec::Support::Helpers::CycleAnalyticsHelpers end ``` ### Factories[](#factories "Permalink") GitLab 使用[factory_bot](https://github.com/thoughtbot/factory_bot)替代測試夾具. * 工廠定義存在于`spec/factories/` ,使用其對應模型的復數形式命名( `User`工廠在`users.rb`中定義). * 每個文件應該只有一個頂級工廠定義. * FactoryBot 方法混入了所有 RSpec 組. 這意味著您可以(并且應該)調用`create(...)`而不是`FactoryBot.create(...)` . * 利用[特征](https://www.rubydoc.info/gems/factory_bot/file/GETTING_STARTED.md#traits)來清理定義和用法. * 定義工廠時,請勿定義結果記錄通過驗證不需要的屬性. * 從工廠實例化時,不要提供測試不需要的屬性. * 工廠不必僅限于`ActiveRecord`對象. [參見示例](https://gitlab.com/gitlab-org/gitlab-foss/commit/0b8cefd3b2385a21cfed779bd659978c0402766d) . ### Fixtures[](#fixtures "Permalink") 所有固定裝置應放置在`spec/fixtures/` . ### Repositories[](#repositories "Permalink") 測試某些功能(例如,合并合并請求)需要在測試環境中具有某種狀態的 Git 存儲庫. GitLab 在某些常見情況下會維護[`gitlab-test`](https://gitlab.com/gitlab-org/gitlab-test)存儲庫-您可以確保該存儲庫的副本與`:repository`特性一起用于項目工廠: ``` let(:project) { create(:project, :repository) } ``` 可以的話,請考慮使用`:custom_repo`特性而不是`:repository` . 這使您可以精確地指定哪些文件將出現在項目存儲庫的`master`分支中. 例如: ``` let(:project) do create( :project, :custom_repo, files: { 'README.md' => 'Content here', 'foo/bar/baz.txt' => 'More content here' } ) end ``` 這將創建一個包含兩個文件的存儲庫,這兩個文件具有默認權限和指定的內容. ### Configuration[](#configuration "Permalink") RSpec 配置文件是更改 RSpec 配置的文件(即`RSpec.configure do |config|`塊). 它們應放在`spec/support/` . 每個文件都應與特定域相關,例如`spec/support/capybara.rb` , `spec/support/carrierwave.rb`等. 如果 helpers 模塊僅適用于某種規格,則應在`config.include`調用中添加修飾符. 例如,如果`spec/support/helpers/cycle_analytics_helpers.rb`僅適用于`:lib`和`type: :model` specs,則應編寫以下內容: ``` RSpec.configure do |config| config.include Spec::Support::Helpers::CycleAnalyticsHelpers, :lib config.include Spec::Support::Helpers::CycleAnalyticsHelpers, type: :model end ``` If a configuration file only consists of `config.include`, you can add these `config.include` directly in `spec/spec_helper.rb`. 對于非常通用的幫助程序,請考慮將它們包括在`spec/support/rspec.rb`文件使用的`spec/fast_spec_helper.rb`文件中. 有關`spec/fast_spec_helper.rb`文件的更多詳細信息,請參見[快速單元測試](#fast-unit-tests) . ### Test environment logging[](#test-environment-logging "Permalink") 在運行測試時,會自動配置并啟動用于測試環境的服務,包括 Gitaly,Workhorse,Elasticsearch 和 Capybara. 在 CI 中運行時,或者如果需要安裝服務,則測試環境將記錄有關設置時間的信息,并產生如下日志消息: ``` ==> Setting up Gitaly... Gitaly set up in 31.459649 seconds... ==> Setting up GitLab Workhorse... GitLab Workhorse set up in 29.695619 seconds... fatal: update refs/heads/diff-files-symlink-to-image: invalid <newvalue>: 8cfca84 From https://gitlab.com/gitlab-org/gitlab-test * [new branch] diff-files-image-to-symlink -> origin/diff-files-image-to-symlink * [new branch] diff-files-symlink-to-image -> origin/diff-files-symlink-to-image * [new branch] diff-files-symlink-to-text -> origin/diff-files-symlink-to-text * [new branch] diff-files-text-to-symlink -> origin/diff-files-text-to-symlink b80faa8..40232f7 snippet/multiple-files -> origin/snippet/multiple-files * [new branch] testing/branch-with-#-hash -> origin/testing/branch-with-#-hash ==> Setting up GitLab Elasticsearch Indexer... GitLab Elasticsearch Indexer set up in 26.514623 seconds... ``` 當在本地運行并且不需要執行任何操作時,將忽略此信息. 如果您始終希望看到這些消息,請設置以下環境變量: ``` GITLAB_TESTING_LOG_LEVEL=debug ``` * * * [Return to Testing documentation](index.html)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看