測試項目框架

測試項目框架是一組套件和使用者介面功能,能輕易撰寫和執行 Julia 套件的測試。

這個框架的主要好處是,測試程式碼可以建構為測試項目,然後輕鬆獨立執行。

Julia VS Code 擴充功能廣泛支援測試項目框架,但測試項目框架本身可以完全獨立於 VS Code 使用。使用者可以在不使用 VS Code 的情況下撰寫測試項目,並使用命令列介面 (或僅使用標準的 Pkg.test 功能) 執行它們。

撰寫測試項目

測試項目框架的核心功能是可以將測試建構為 @testitem 區塊,然後個別執行這些區塊,而不用一次執行所有測試。典型的 @testitem 可能如下所示

@testitem "First tests" begin
    x = foo("bar")

    @test length(x)==3
    @test x == "bar"
end

@testitem 有一個名稱 (例如「第一個測試」),以及 begin ... end 區塊中的一些程式碼。@testitem 內的程式碼必須能單獨執行,例如不能依賴 @testitem 外部的程式碼,除非在 @testitem 內明確匯入或包含該程式碼。這種情況只有一個例外:@testitem 內的程式碼會在暫時模組中執行,其中已執行 using Testusing MYPACKAGENAME,因此可以從 Test 模組或您開發的套件匯出的任何內容都能直接使用。在以上範例中,這會套用至 foo 函數 (假設定義於受測套件中) 和 @test 巨集。

@testitem 可以在套件中的任何位置出現。它們不需要位於 test 資料夾中,也不需要位於 test/runtests.jl 包含的檔案中。事實上,@testitem 甚至可以位於您的常規套件程式碼中,例如位在它們所測試程式碼旁邊。在這種情況下,您只需建立對 TestItems.jl 套件的相依關係,以便存取 @testitem 巨集。如果您有一個套件 MyPackage,那麼檔案 src/MyPackage.jl 可能如下所示

module MyPackage

using TestItems

export foo

foo(x) = x

@testitem "First tests" begin
    x = foo("bar")

    @test length(x)==3
    @test x == "bar"
end

end

如果您不喜歡這種內嵌 @testitem 的樣式,您也可以在測試資料夾的 Julia 檔案中加入 @testitem 塊。

在 VS Code 中執行測試項目

當您在 VS Code 中開啟一個 Julia 套件,並且已安裝 Julia 擴充功能,它將持續 (每次按鍵後) 尋找 Julia 檔案中所有 @testitem。如果找到,它們將出現在 UI 中的不同位置。

您可以在 VS Code 中的「測試」活動欄位找到所有偵測到的 @testitem

Test activity bar

然後,測試活動區域會提供您選項,可執行個別 @testitem、查看結果等。

VS Code 也會在文字編輯器本身中將一個小的執行按鈕置於每個偵測到的 @testitem 旁邊。

Test run button

除了所有這些允許您執行測試的 UI 元素外,還有一個 UI 可顯示測試結果。舉例來說,當您執行測試,且某些測試失敗時,擴充功能會收集所有這些測試失敗,然後以有條理的方式將它們顯示在程式碼中特定測試失敗處。

Test error detail

特別是在您使用大的測試檔案執行大量測試時,這將使您更容易找到失敗的特定測試,無需再在 REPL 中搜尋檔案和行資訊!

從命令列執行測試

您可以使用 TestItemRunner.jl 套件來執行 @testitem,作為傳統 Pkg.test 工作流程的一部份。

要為使用 @testitem 的套件啟用與 Pkg.test 的整合,您只需要做兩件事

  1. TestItemRunner.jl 新增至套件的測試相依性
  2. 將下列程式碼加入套件的 test/runtests.jl 檔案
using TestItemRunner

@run_package_tests

標記

您現在可以將標記新增至 @testitem。標記可以在 VS Code UI 和 TestItemRunner.jl 中使用,以過濾您想要執行的測試項目。

新增標記的語法如下

@testitem "My testitem" tags=[:skipci, :important] begin
    x = foo("bar")

    @test length(x)==3
    @test x == "bar"
end

然後,您可以使用這些相同的標籤過濾 VS Code UI 中的測試清單。

Test item tags

此外,您可以在 test/runtests.jl 中使用標籤過濾將通過傳統 Pkg.test 進入點執行的測試清單。

using TestItemRunner

@run_package_tests filter=ti->!(:skipci in ti.tags)

篩選 部分下方有更完整的描述,說明 @run_package_tests 巨集的新篩選關鍵字。

VS Code 中的平行測試執行

VS Code 擴充功能有一個設定控制您想要用來進行平行測試執行的 Julia 程序數量

Test num test processes

預設值為 1,因此您必須更改此值才能使用平行測試執行功能。0 的值將使用與處理器一樣多的測試程序。

一旦您設定超過一個測試程序,個別 @testitem 將會平行執行。

這裡有一個權衡:更多的測試程序表示需要更多的記憶體,而且潛在也會產生額外的開銷,讓所有程序啟動並準備好實際執行 @testitem

管理測試程序

在 VS Code 中透過這個新的測試使用者界面啟動的測試流程並不會自動終止,也就是說它們會繼續執行並佔用記憶體及其他資源。這當然有不少好處,其中一項就是,一旦測試流程啟動並執行,@testitem 就會執行得非常快,不過在某些情況下,您可能還是希望直接終止所有目前執行的測試流程。

要達成這個目的,所有測試流程都會顯示在 Julia 工作空間中,並會顯示其他可能正在執行的 REPL 或筆記本流程。您可以透過按一下 停止測試流程 按鈕,然後透過這個使用者界面終止 Julia 測試流程。在這個螢幕截圖中有四個測試流程正在執行

過濾 TestItemRunner.jl 中的支援

您可以將一般過濾函式傳遞給 @run_package_tests巨集,以選擇您想要執行的 @testitem。上方的區段使用標籤來選擇要執行的測試,但您也可以根據 @testitem 定義所在的文件檔名或 @testitem的名稱進行過濾。

執行的方式是,您可以將過濾函式傳遞給 @run_package_tests 巨集。這個過濾函式會在您的專案中偵測到的每個 @testitem中呼叫一次,而且如果這個測試項目應該執行,則該函式必須傳回 true;如果不應該執行,則傳回 false@run_package_tests會將包含特定測試項目資訊元資料的名稱組傳遞給您的過濾函式,亦即 filename 欄位(定義 @testitem的文件檔位的完整路徑)、name(您所定義的 @testitem的名稱)及 tagsSymbol 的向量)。有了這些資訊,您可以撰寫任意複雜的過濾條件。例如,我在這裡過濾任何具有 :skipci 標籤的 @testitem,而且我只執行在一個特定文件檔中定義的測試

@run_package_tests filter=ti->( !(:skipci in ti.tags) && endswith(ti.filename, "test_foo.jl") )

預設匯入選項

當您撰寫 @testitem 時,預設會透過隱藏的 using 敘述匯入正測試的套件及 Test 套件。在某些情況下這可能不太理想,因此可以透過 default_imports 選項來控制這種行為,該選項接受 Bool 值。如要停用這些預設匯入,您會撰寫

@testitem "Another test for foo" default_imports=false begin
    using MyPackage, Test

    x = foo("bar")

    @test x != "bar"
end

請注意,現在我們需要手動將 using MyPackage, Test 這個行加入我們的 @testitem,這樣我們才能存取 foo 函式及 @test 巨集。

在各 @testitem 中共用程式碼

預設情況下,@testitem 彼此之間不共用任何程式碼,而且彼此之間也沒有相依性。這些屬性讓 @testitem 得以單獨執行,但有時您會希望在多個 @testitem 之間共用共用程式碼。測試項目架構提供了兩個巨集來達成這個目的:@testsnippet@testmodule。這兩個巨集都可以出現在套件中的任何 .jl 文件檔中。

測試片段

@testsnippet 是程式碼區塊,個別 @testitem 的程式碼在執行自己的程式碼之前可以執行這個區塊。如果 @testitem 使用特定 @testsnippet,則系統在每次執行 @testitem 時都會執行該片段。

@testsnippet 的定義可能會如下所示

@testsnippet MySnippet begin
    foo = "Hello world"
end

@testitem 可以透過使用 setup 關鍵字來利用這個片段,如下所示

@testitem "My test item" setup=[MySnippet] begin
    @test foo == "Hello world"
end

測試模組

@testmodule 定義一個可以從 @testitem 存取的 Julia 模組。此模組只會在每個 Julia 測試程式中執行一次。如果例如有兩個 @testitem 依賴於一個 @testmodule,則只會評估一次,然後整個模組就會提供給兩個 @testitem 使用。

@testmodule 的定義可能如下所示

@testmodule MyModule begin
    foo = "Hello world"
end

@testitem 可以再次使用 setup 關鍵字來使用此模組。與 @testsnippet 不同的是,@testmodule 的內容在正規 Julia module 內部執行,因此要存取其中的內容,必須將模組名稱作為前綴附加到測試模組中定義的任何名稱。使用剛才定義的 @testmodule@testitem 可能如下所示

@testitem "My test item" setup=[MyModule] begin
    @test MyModule.foo == "Hello world"
end

請注意我們如何使用 MyModule.foo 表達式來存取 foo

偵錯 @testitem

@testitem 可以透過 Debug Test 指令啟動,在偵錯工具中執行。此指令可以在 VS Code UI 的不同位置存取。在測試主測試檢視中,可在此找到

Testitem debugging 1

您也可以在文字編輯器中右鍵按一下執行測試圖示來選擇偵錯選項

Testitem debugging 2

當測試項目於偵錯工具中執行時,您可以在受測程式碼或 @testitem 本身中設定中斷點,然後使用 Julia VS Code 偵錯工具的所有常規功能。

程式碼涵蓋率

在 Julia 1.11 及更高版本中,您可以在程式碼涵蓋率模式中執行測試項目,並直接在 VS Code 中顯示程式碼涵蓋率結果。

要在程式碼涵蓋率模式中執行測試項目,請使用 Run Tests with Coverage 指令啟動它們。此指令同時在主測試檢視中可用

Testitem coverage 1

以及在文字編輯器的內容功能表中

Testitem coverage 2

然後會在 VS Code UI 中以不同的方式顯示涵蓋率結果。例如,摘要檢視會顯示每個檔案的涵蓋率

Testitem coverage 2

您可以在文字編輯器中看到詳細的行涵蓋率資訊

Testitem coverage 2

涵蓋率結果也會直接顯示在 VS Code UI 的常規瀏覽器部分。