從 VSTest 遷移到 Microsoft。測試平台(MTP)

在本文中,你將學習如何從 VSTest 遷移到 MTP。

本文重點介紹遷移步驟與論元映射。

如果你還需要選擇平台,可以先從 測試平台總覽開始。

如果您需要dotnet test模式的詳細行為,請參考測試dotnet test

如果你需要一份平台與擴充功能命令列選項的單一清單,請參考 MTP CLI 選項參考

選擇使用 MTP

遷移的第一步是選擇使用 MTP。

針對所有測試框架,在解決方案中的所有測試專案加入 <OutputType>Exe</OutputType>。 之後,請遵照特定架構的指導。

MSTest

MTP 自 3.2.0 起由 MSTest 支援。 不過,建議您更新至最新的可用 MSTest 版本。

若要選擇加入,請在<EnableMSTestRunner>true</EnableMSTestRunner>檔案的PropertyGroup標籤下新增Directory.Build.props

備註

使用 MSTest.Sdk 時,預設使用 MTP,除非 <UseVSTest>true</UseVSTest> 另有說明。

NUnit

MTP 自 5.0.0 起由 NUnit3TestAdapter 支援。

若要選擇加入,請在<EnableNUnitRunner>true</EnableNUnitRunner>檔案的PropertyGroup標籤下新增Directory.Build.props

xUnit.net

MTP 從 xunit.v3 開始支援。

若要選擇加入,請在<UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>檔案的PropertyGroup標籤下新增Directory.Build.props

dotnet test

選擇啟用 .NET 9 SDK 與更早版本

在 .NET 9 SDK 及更早版本中,沒有對 MTP 的原生支援。 支援建置在 VSTest 基礎結構之上。 要使用它,請在<TestingPlatformDotnetTestSupport>true</TestingPlatformDotnetTestSupport>檔案中PropertyGroup下新增Directory.Build.props

這很重要

在此模式下執行 MTP 支援時,您需要使用 -- 以將原來的參數與新平台的參數 dotnet test 區分開來。 例如: dotnet test --no-build -- --list-tests

選擇加入 .NET 10 SDK 和更新版本

從 .NET 10 SDK 開始,提供對 MTP 的原生支援。 若要使用它,您必須指定測試執行器,如 Microsoft.Testing.Platformglobal.json所示:

{
  "test": {
    "runner": "Microsoft.Testing.Platform"
  }
}

這很重要

在此模式下,不再使用額外的 -- 部分。

更新 dotnet test 呼叫

dotnet test 命令列選項分為兩類:與建置相關的參數和與測試相關的參數。

組建相關的引數與測試平台無關,因此不需要針對新平台進行更新。 此處列出與組建相關的引數:

  • -a|--arch <ARCHITECTURE>
  • --artifacts-path <ARTIFACTS_DIR>
  • -c|--configuration <CONFIGURATION>
  • -f|--framework <FRAMEWORK>
  • -e|--environment <NAME="VALUE">
  • --interactive
  • --no-build
  • --nologo
  • --no-restore
  • -o|--output <OUTPUT_DIRECTORY>
  • --os <OS>
  • -r|--runtime <RUNTIME_IDENTIFIER>
  • -v|--verbosity <LEVEL>

與測試相關的引數是 VSTest 特定的,因此需要轉換以符合新平台。 下表顯示 VSTest 引數與新平臺之間的對應:

VSTest 引數 新平台論點
--test-adapter-path <ADAPTER_PATH> 對MTP無關
--blame 對MTP無關
--blame-crash --crashdump (需要 損毀傾印擴充功能
--blame-crash-dump-type <DUMP_TYPE> --crashdump-type (需要 損毀傾印擴充功能
--blame-crash-collect-always 不支援
--blame-hang --hangdump (需要 Hang dump 外掛程式
--blame-hang-dump-type <DUMP_TYPE> --hangdump-type (需要 Hang dump 外掛程式
--blame-hang-timeout <TIMESPAN> --hangdump-timeout (需要 Hang dump 外掛程式
--collect <DATA_COLLECTOR_NAME> 取決於資料收集器
-d\|--diag <LOG_FILE> --diagnostic
--filter <EXPRESSION> 取決於所選的測試框架
-l\|--logger <LOGGER> 取決於記錄儀
--results-directory <RESULTS_DIR> --results-directory <RESULTS_DIR>
-s\|--settings <SETTINGS_FILE> 取決於所選的測試框架
-t\|--list-tests --list-tests
-- <RunSettings arguments> --test-parameterVSTestBridge提供)

--collect

--collect 是 VSTest 中任何資料收集器的一般擴充點。 MTP 的擴充性模型不同,且沒有一個集中式論證必須所有資料收集者使用。 透過 MTP,每個資料收集器都可以新增自己的命令列選項。 例如,透過 VSTest 執行 Microsoft CodeCoverage 可能類似下列內容:

dotnet test --collect "Code Coverage;Format=cobertura"

有了MTP,這變成:

dotnet test --coverage --coverage-output-format cobertura

這很重要

如前所述,在使用以 VSTest 為基礎的 MTP dotnet test 時,需要在傳遞給平台的參數之前加上額外的 --。 所以,這變成了 dotnet test -- --coverage --coverage-output-format cobertura

--filter

--filter 是以 VSTest 為基礎的篩選器。

即使運行 MTP,MSTest 和 NUnit 也支援相同的過濾格式。

xUnit.net,在 MTP 執行時不支援相同的濾波器格式。 您必須從以 VSTest 為基礎的篩選移轉至 xunit.v3 中的新篩選支援,這是使用下列命令列選項提供的。

xUnit.net 具體選項:

  • --filter-class
  • --filter-not-class
  • --filter-method
  • --filter-not-method
  • --filter-namespace
  • --filter-not-namespace
  • --filter-trait
  • --filter-not-trait
  • --filter-query

如需詳細資訊,請參閱 xUnit.net 的 Microsoft.Testing.Platform 檔xUnit.net 的查詢篩選語言

--logger

VSTest 中通常稱為「logger」的部分,在 MTP 中則稱為「reporter」。 在 MTP 中,日誌明確用於診斷。

類似於 --collect--logger 是 VSTest 中任何記錄器(或在 MTP 語境下,任何 報告生成器)的通用擴充點。 每個 MTP 報告器都可以自行新增命令列選項,因此沒有像 VSTest --logger那樣集中式的命令列選項。

非常常用的 VSTest 記錄器之一是 TRX 記錄器。 此記錄器通常以下列方式調用:

dotnet test --logger trx

使用 MTP 時,指令變為:

dotnet test --report-trx

這很重要

若要使用 --report-trx,您必須安裝 Microsoft.Testing.Extensions.TrxReport NuGet 套件。

這很重要

如前所述,使用 MTP 搭配 VSTest 為基礎 dotnet test 時,在傳遞給平台的參數之前,需要額外的 --。 所以,這變成了 dotnet test -- --report-trx

--settings

VSTest 可用 --settings 來指定測試回合的 RunSettings 檔案。 RunSettings 不被核心 MTP 支援,並被更現代的 testconfig.json 設定檔取代。 不過,MSTest 和 NUnit 在執行 MTP 時仍支援舊版 RunSettings,且 --settings 仍被支援。

vstest.console.exe

如果您直接使用 vstest.console.exe ,我們建議將其替換為命令 dotnet test

測試總管

使用 Visual Studio 或 Visual Studio Code 測試檔案總管時,可能需要啟用 MTP 支援。

Visual Studio

Visual Studio 測試檔案總管自 17.14 版本起支援 MTP。 如果您使用的是舊版,您可能需要將 Visual Studio 更新為最新版本。

Visual Studio Code

Visual Studio Code 搭配 C# DevKit 支援 MTP。

Azure DevOps

使用 Azure DevOps 任務時,可能需要更新管線以使用 MTP,視你使用的任務而定。

VSTest 工作

如果您在 Azure DevOps 中使用 VSTest 工作 ,您可以將它取代為 .NET Core 工作

.NET Core CLI 任務

  • 如果您已將自訂的 arguments 傳遞至工作,請遵循 dotnet test 移轉的相同指導方針。

  • 如果你使用 DotNetCoreCLI 任務,但未透過 global.json 檔案選擇啟用 .NET 10 SDK 及更高版本的原生 MTP 體驗,那麼你將需要設定該任務的 arguments 來正確指向過去所指向的結果目錄,以及所需的 TRX 報告。 例如:

    - task: DotNetCoreCLI@2
      displayName: Run unit tests
      inputs:
        command: 'test'
        arguments: '-- --report-trx --results-directory $(Agent.TempDirectory)'
    

VSTest 與 MTP 的行為差異

執行零測試

如果測試組件完全沒執行測試,VSTest 會容忍並成功退出。 然而,MTP 失敗,並顯示退出代碼 8。 有多種方法可以繞過這個問題:

  • 執行測試時傳遞 --ignore-exit-code 8

  • 如果你想忽略特定測試專案的退出碼,可以在專案檔案中加入以下內容:

    <PropertyGroup>
      <TestingPlatformCommandLineArguments>$(TestingPlatformCommandLineArguments) --ignore-exit-code 8</TestingPlatformCommandLineArguments>
    </PropertyGroup>
    
  • 使用 TESTINGPLATFORM_EXITCODE_IGNORE 環境變數。

Console.InputEncoding 的保留

如果你在一個代碼頁明確更改過的主控台執行測試(例如在 Azure DevOps 中,代碼頁設為 65001,對應 UTF8),VSTest 和 MTP 的行為可能會不同。

  • 在使用 MTP 時,該編碼能夠一直被保留。
  • 當 VSTest 不以隔離模式(vstest.console 的預設行為)執行時,該編碼會被保留,類似於 MTP。
  • 當 VSTest 以隔離模式(預設行為 dotnet test)執行時,該編碼不會被保留在執行測試的 testhost 程序中。

小提示

VSTest 隔離模式不保留編碼的原因,是因為測試主機程序是以 CreateNoWindow = true開始的。 所以它沒有連接到原本的主機。

如果你有一個測試啟動另一個子程序並重定向其標準輸出,若以下條件全部適用,你可能會遇到問題:

  • 主控台代碼頁設定為 65001(UTF8)。 這種情況在人工耳蝸上可能有,但一般不會在本地發生。 要達到類似 CI 的局部行為,先執行 chcp 65001 測試。
  • 子程序以非 UTF8 編碼開始。 如果您自己的測試也設定了 CreateNoWindow = true,這種情況也可能發生。

這尤其棘手的是,子程序不預期會看到 UTF8 BOM(Byte-Order-Mark)位元組,而在 .NET Framework 的前述情境中可能會看到。

由於這種行為差異可能特別針對 BOM 位元組造成問題,一個變通方法是在組合語言初始化時將 InputEncoding 設定為 UTF8,但不含 BOM:

Console.InputEncoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);

另一種解決方法是不使用 CreateNoWindow = true 來進行標準輸入重定向的子程序。