Migrowanie z programu VSTest do Microsoft. Testing.Platform (MTP)

Z tego artykułu dowiesz się, jak przeprowadzić migrację z programu VSTest do MTP.

Ten artykuł koncentruje się na krokach migracji i mapowaniu argumentów.

Jeśli nadal musisz wybrać platformę, zacznij od omówienia platform testowych.

Jeśli potrzebujesz szczegółowego zachowania trybów dotnet test, odwołaj się do polecenia Testowanie za pomocą dotnet test.

Jeśli potrzebujesz pojedynczej listy opcji wiersza polecenia platformy i rozszerzeń, zobacz dokumentację opcji CLI MTP.

Wskazówka

Aby zautomatyzować migrację w skali całego repozytorium za pomocą asystenta kodowania AI, zainstaluj wtyczki dotnet-test i dotnet-test-migration z pakietu .NET Agent Skills. Poproś test-migration agenta o wykrycie i migrację konfiguracji testowej lub wywołaj migrate-vstest-to-mtp umiejętność na potrzeby tej konkretnej migracji. Przejrzyj wygenerowane zmiany, zanim je scalisz.

Wyrażanie zgody na korzystanie z protokołu MTP

Pierwszym krokiem migracji jest skorzystanie z protokołu MTP.

Dla wszystkich frameworków testowych dodaj <OutputType>Exe</OutputType> do wszystkich projektów testowych w rozwiązaniu. Następnie postępuj zgodnie ze wskazówkami specyficznymi dla platformy.

MSTest

Protokół MTP jest obsługiwany przez bibliotekę MSTest, począwszy od wersji 3.2.0. Zalecamy jednak zaktualizowanie do najnowszej dostępnej wersji MSTest.

Aby wyrazić zgodę, dodaj <EnableMSTestRunner>true</EnableMSTestRunner> pod elementem PropertyGroup w pliku Directory.Build.props.

Uwaga / Notatka

W przypadku korzystania z zestawu MSTest.Sdk protokół MTP jest używany domyślnie, chyba że <UseVSTest>true</UseVSTest> zostanie określony.

NUnit

MTP jest obsługiwany przez NUnit3TestAdapter począwszy od wersji 5.0.0.

Aby wyrazić zgodę, dodaj <EnableNUnitRunner>true</EnableNUnitRunner> pod elementem PropertyGroup w pliku Directory.Build.props.

xUnit.net

MTP jest obsługiwane od wersji xunit.v3.

Aby wyrazić zgodę, dodaj <UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner> pod elementem PropertyGroup w pliku Directory.Build.props.

dotnet test

Zgoda na zestaw .NET 9 SDK i jego wcześniejsze wersje

W .NET 9 zestawach SDK i starszych nie ma rodzimej obsługi protokołu MTP dla dotnet test. Obsługa jest oparta na infrastrukturze VSTest. Aby tego użyć, dodaj <TestingPlatformDotnetTestSupport>true</TestingPlatformDotnetTestSupport> pod PropertyGroup w pliku Directory.Build.props.

Ważne

W przypadku uruchamiania obsługi MTP w tym trybie należy dodać -- , aby oddzielić dotnet test argumenty od nowych argumentów platformy. Na przykład dotnet test --no-build -- --list-tests.

Zgoda na korzystanie z zestawu .NET 10 SDK i nowszych wersji

Począwszy od zestawu SDK .NET 10, zapewnia się natywną obsługę MTP. Aby go użyć, należy określić moduł uruchamiający testy, jak Microsoft.Testing.Platform w global.json:

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

Ważne

W tym trybie dodatkowa -- nie jest już wymagana. Zachowaj je, aby przekazywać argumenty aplikacji testowej jednoznacznie.

Zaktualizuj wywołania dotnet test

Opcje dotnet test wiersza polecenia są podzielone na dwie kategorie: argumenty związane z kompilacją i powiązane z testami.

Argumenty związane z kompilacją nie mają znaczenia dla platformy testowej i w związku z tym nie muszą być aktualizowane dla nowej platformy. Argumenty związane z kompilacją są wymienione tutaj:

  • -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>

Mimo że --arch pozostaje opcją związaną z kompilacją, zastępuje architekturę wybraną przez program VSTest za pomocą polecenia RunConfiguration.TargetPlatform. Przekaż --arch do samego dotnet test, przed jakimkolwiek separatorem --.

Na przykład zmigruj to polecenie projektu VSTest:

dotnet test MyTests.csproj -c Debug -- RunConfiguration.TargetPlatform=x86 /Parallel

W przypadku zestawu SDK platformy .NET 10 i nowszych wersji użyj następującego polecenia MTP:

dotnet test --project MyTests.csproj -c Debug --arch x86

Zastąp x86 elementem x64, aby jako architekturę docelową ustawić x64. Domyślnie usługa MTP uruchamia moduły testowe równolegle, więc /Parallel nie wymaga zamiany. Aby ograniczyć równoległość na poziomie modułu, użyj polecenia --max-parallel-test-modules <NUMBER>.

Ważne

Nie można połączyć --solution z --arch, --os ani --runtime. Te opcje ustawiają RuntimeIdentifier jako globalną właściwość MSBuild, a kompilacje rozwiązania nie obsługują globalnej właściwości RuntimeIdentifier. Aby przetestować rozwiązanie w różnych architekturach, należy wywołać każdy projekt testowy oddzielnie lub ustawić RuntimeIdentifier w poszczególnych projektach testowych.

Na przykład zastąp te cztery polecenia VSTest na poziomie rozwiązania:

dotnet test MySolution.sln -c Debug -- RunConfiguration.TargetPlatform=x86 /Parallel
dotnet test MySolution.sln -c Release -- RunConfiguration.TargetPlatform=x86 /Parallel
dotnet test MySolution.sln -c Debug -- RunConfiguration.TargetPlatform=x64 /Parallel
dotnet test MySolution.sln -c Release -- RunConfiguration.TargetPlatform=x64 /Parallel

W przypadku zestawu .NET 10 SDK i nowszych wersji użyj macierzy na poziomie projektu:

$testProjects = @("tests/A.Tests/A.Tests.csproj", "tests/B.Tests/B.Tests.csproj")
$testRunFailed = $false
foreach ($configuration in "Debug", "Release") {
    foreach ($architecture in "x86", "x64") {
        foreach ($testProject in $testProjects) {
            dotnet test --project $testProject -c $configuration --arch $architecture
            if ($LASTEXITCODE -ne 0) {
                $testRunFailed = $true
            }
        }
    }
}
if ($testRunFailed) {
    throw "One or more test runs failed."
}

Argumenty związane z testem są specyficzne dla programu VSTest i dlatego należy je przekształcić w celu dopasowania do nowej platformy. W poniższej tabeli przedstawiono mapowanie między argumentami VSTest a nową platformą:

Argument VSTest Nowy parametr platformy
--test-adapter-path <ADAPTER_PATH> Nie dotyczy MTP
--blame Nie dotyczy MTP
--blame-crash --crashdump (wymaga rozszerzenia zrzutu pamięci)
--blame-crash-dump-type <DUMP_TYPE> --crashdump-type (wymaga rozszerzenia zrzutu pamięci)
--blame-crash-collect-always Niewspierane
--blame-hang --hangdump (wymaga rozszerzenia "Hang dump")
--blame-hang-dump-type <DUMP_TYPE> --hangdump-type (wymaga rozszerzenia "Hang dump")
--blame-hang-timeout <TIMESPAN> --hangdump-timeout (wymaga rozszerzenia "Hang dump")
--collect <DATA_COLLECTOR_NAME> Zależy od modułu zbierającego dane
-d\|--diag <LOG_FILE> --diagnostic
--filter <EXPRESSION> Zależy od wybranej platformy testowej
-l\|--logger <LOGGER> Zależy od rejestratora
--results-directory <RESULTS_DIR> --results-directory <RESULTS_DIR>
-s\|--settings <SETTINGS_FILE> Zależy od wybranej platformy testowej
-t\|--list-tests --list-tests
-- RunConfiguration.TargetPlatform=<ARCHITECTURE> --arch <ARCHITECTURE> dla wywołania projektu
/Parallel Nie jest wymagana żadna opcja. Domyślnie MTP uruchamia moduły testowe równolegle.
-- <RunSettings arguments> --test-parameter (dostarczone przez VSTestBridge)

--collect

--collect to ogólny punkt rozszerzalności w programie VSTest dla dowolnego modułu zbierającego dane. Model rozszerzalności MTP jest inny i nie ma tak scentralizowanego argumentu, który ma być używany przez wszystkie moduły zbierające dane. W przypadku protokołu MTP każdy moduł zbierający dane może dodać własną opcję wiersza polecenia. Na przykład uruchomienie programu Microsoft CodeCoverage za pośrednictwem programu VSTest może być podobne do następujących:

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

W przypadku protokołu MTP staje się to następujące:

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

Ważne

Aby używać elementu --coverage, każda docelowa aplikacja testowa musi odwoływać się bezpośrednio do pakietu NuGet Microsoft.Testing.Extensions.CodeCoverage lub za pośrednictwem konfiguracji zestawu SDK do testów albo profilu, który go zawiera.

Ważne

Jak wyjaśniono wcześniej, w przypadku korzystania z protokołu MTP z opartą dotnet testna narzędziu VSTest dodatkowe -- informacje są potrzebne przed przekazaniem argumentów do platformy. Tak więc to staje się dotnet test -- --coverage --coverage-output-format cobertura.

--filter

--filter jest filtrem opartym na programie VSTest.

Narzędzia MSTest i NUnit obsługują ten sam format filtru, nawet w przypadku uruchamiania z użyciem protokołu MTP.

xUnit.net nie obsługuje tego samego formatu filtru podczas uruchamiania z MTP. Należy przeprowadzić migrację z filtru opartego na VSTest do nowej obsługi filtru w xunit.v3, co jest realizowane za pomocą następujących opcji wiersza poleceń.

Opcje specyficzne dla xUnit.net:

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

Aby uzyskać więcej informacji, zobacz dokumentację Microsoft.Testing.Platform dotyczącą języka xUnit.net i języka filtrowania zapytań dla xUnit.net.

Wskazówka

Jeśli rozwiązanie miesza struktury testowe korzystające z różnych składni filtrów (na przykład MSTest i xUnit.net), możesz warunkowo kierować argumenty specyficzne dla struktury przy użyciu TestingPlatformCommandLineArguments właściwości MSBuild. Aby uzyskać szczegółowe informacje, zobacz Rozwiązania z mieszanymi strukturami testowymi lub rozszerzeniami.

--logger

To, co w programie VSTest zwykle nazywa się "rejestratorem", jest określane jako "reporter" w MTP. W usłudze MTP rejestrowanie jest jawnie przeznaczone tylko do celów diagnostycznych.

Podobnie jak --collect, --logger jest ogólnym punktem rozszerzalności w programie VSTest dla dowolnego rejestratora (lub, w kontekście protokołu MTP, dowolnego reportera). Każdy reporter MTP ma swobodę dodawania własnej opcji wiersza polecenia, w związku z czym nie ma scentralizowanej opcji wiersza polecenia, takiej jak w VSTest.

Jednym z bardzo często używanych rejestratorów VSTest jest rejestrator TRX. Ten rejestrator jest zwykle wywoływany w następujący sposób:

dotnet test --logger trx

W przypadku protokołu MTP polecenie staje się następujące:

dotnet test --report-trx

Ważne

Aby używać --report-trx, każda docelowa aplikacja testowa musi bezpośrednio odwoływać się do pakietu NuGet Microsoft.Testing.Extensions.TrxReport lub za pośrednictwem konfiguracji albo profilu zestawu SDK testów, które go zawierają.

Ważne

Jak wyjaśniono wcześniej, w przypadku korzystania z protokołu MTP z opartą dotnet testna narzędziu VSTest dodatkowe -- informacje są potrzebne przed przekazaniem argumentów do platformy. Tak więc to staje się dotnet test -- --report-trx.

GitHub Actions opcje reportera są specyficzne dla pakietu i nie są zamienne:

Pakiet reportera Opcja MTP
Microsoft. Testing.Extensions.GitHubActionsReport --report-gh
GitHubActionsTestLogger --report-github

Aplikacja testowa rozpoznaje opcję tylko wtedy, gdy pakiet, który jest jego właścicielem, jest zainstalowany i zarejestrowany. Jeśli na przykład zmigrujesz --logger GitHubActions i zachowasz pakiet GitHubActionsTestLogger, zastąp polecenie VSTest:

dotnet test --logger GitHubActions

W przypadku zestawu .NET 10 SDK i nowszych wersji użyj:

dotnet test --report-github

W przypadku zestawu SDK platformy .NET 9 i wcześniejszych wersji użyj zamiast tego elementu dotnet test -- --report-github.

--settings

Narzędzia VSTest's --settings są używane do określenia pliku RunSettings dla uruchomienia testów. Element RunSettings nie jest obsługiwany przez rdzeń MTP i został zastąpiony bardziej nowoczesnym testconfig.json plikiem konfiguracji. Jednak narzędzia MSTest i NUnit nadal obsługują stare ustawienia RunSettings podczas uruchamiania protokołu MTP i --settings nadal są obsługiwane.

vstest.console.exe

Jeśli używasz vstest.console.exe bezpośrednio, zalecamy zastąpienie go poleceniem dotnet test .

Eksplorator testów

W przypadku korzystania z eksploratora testów Visual Studio lub Visual Studio Code może być konieczne włączenie obsługi protokołu MTP.

Visual Studio

Visual Studio Eksplorator testów obsługuje protokół MTP począwszy od wersji 17.14. Jeśli używasz starszej wersji, może być konieczne zaktualizowanie programu Visual Studio do najnowszej wersji.

Visual Studio Code

Visual Studio Code z zestawem deweloperskim języka C# obsługuje protokół MTP.

Azure DevOps

W przypadku korzystania z zadań Azure DevOps, może być konieczne zaktualizowanie potoku, aby użyć protokołu MTP, w zależności od konkretnego zadania, którego używasz.

VsTest, zadanie

Jeśli używasz zadania VSTest w usłudze Azure DevOps, możesz zastąpić je zadaniem platformy .NET Core.

Zadanie interfejsu wiersza polecenia platformy .NET Core

  • Jeśli przekazano niestandardowe arguments do zadania, postępuj zgodnie z tymi samymi wskazówkami dotyczącymi migracji dotnet test.

  • Jeśli używasz DotNetCoreCLI bez zaznaczenia opcji natywnego środowiska MTP dla zestawu SDK .NET 10 i nowszych za pośrednictwem pliku global.json, zadanie arguments musi być ustawione tak, aby prawidłowo wskazywać katalog wyników, który był wcześniej używany, oraz żądany raport TRX. Przykład:

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

    Aplikacje testowe w tym przykładzie muszą zarejestrować plik Microsoft.Testing.Extensions.TrxReport. Dodaj pakiet bezpośrednio lub użyj konfiguracji lub profilu zestawu SDK testów, który go zawiera.

Różnice behawioralne między narzędziami VSTest i MTP

Uruchamianie testów zerowych

Jeśli zestaw testowy nie uruchomił żadnych testów, program VSTest toleruje to i zakończy się powodzeniem. Jednak MTP kończy się niepowodzeniem z kodem wyjścia 8. Istnieje wiele sposobów obejścia tego:

  • Przekaż --ignore-exit-code 8 podczas uruchamiania testów.

  • Jeśli chcesz zignorować ten kod zakończenia dla określonego projektu testowego, dodaj następujący kod w pliku projektu:

    <PropertyGroup>
      <TestingPlatformCommandLineArguments>$(TestingPlatformCommandLineArguments) --ignore-exit-code 8</TestingPlatformCommandLineArguments>
    </PropertyGroup>
    
  • Użyj zmiennej środowiskowej TESTINGPLATFORM_EXITCODE_IGNORE .

Zachowanie Console.InputEncoding

Jeśli uruchamiasz testy w konsoli, w której strona kodowa została jawnie zmieniona (na przykład w Azure DevOps, strona kodowa jest ustawiona na 65001, która odpowiada UTF8), zachowanie może być inne między programem VSTest i MTP.

  • W przypadku protokołu MTP kodowanie jest zawsze zachowywane.
  • Jeśli program VSTest nie działa w trybie izolacji (domyślne zachowanie vstest.console), to kodowanie jest zachowywane, podobnie jak W przypadku protokołu MTP.
  • W programie VSTest uruchomionym w trybie izolacji (domyślne zachowanie dotnet test) kodowanie nie jest zachowywane w hoście testowym, czyli w procesie, w którym są uruchamiane testy.

Wskazówka

Powodem, dla którego kodowanie nie jest zachowywane w trybie izolacji VSTest, jest to, że proces testhost jest uruchamiany z CreateNoWindow = true. Nie jest więc dołączony do oryginalnej konsoli.

Jeśli masz test, który uruchamia kolejny proces podrzędny i przekierowuje jego standardowe dane wyjściowe, możesz napotkać problemy, jeśli wszystkie następujące elementy mają zastosowanie:

  • Strona kodowa konsoli jest ustawiona na wartość 65001 (UTF8). Może tak być w przypadku CI, ale z reguły nie lokalnie. Aby uzyskać lokalne zachowanie podobne do tego w systemie CI, uruchom polecenie chcp 65001 przed uruchomieniem testów.
  • Proces podrzędny rozpoczyna się od kodowania innego niż UTF8. Może się to również zdarzyć, jeśli twój własny test również ustawia wartość CreateNoWindow = true.

Jest to szczególnie problematyczne, gdy proces podrzędny nie oczekuje, że napotka bajt BOM UTF8 (znak kolejności bajtów), na co może trafić w poprzednim scenariuszu w środowisku .NET Framework.

Ponieważ ta różnica w zachowaniu może być problematyczna w szczególności dla bajtu BOM, obejściem jest ustawienie InputEncoding podczas inicjowania zestawu na UTF8 bez BOM:

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

Innym obejściem tego problemu jest brak użycia CreateNoWindow = true w przypadku procesów podrzędnych, które przekierowują standardowe dane wejściowe.