Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
I MTP-serverläge kan en editor, en IDE, ett anpassat testgränssnitt eller ett annat testverktyg starta en testapplikation och styra testidentifiering och testkörning via JSON-RPC. Använd serverläge när verktyget behöver testmetadata, körning av valt test, förloppsuppdateringar eller resultatartefakter utan att parsa terminalutdata. För normala kommandorads- och CI-körningar kör du testprogrammet direkt eller använder dotnet test.
För identifiering med ett skott utan en beständig anslutning använder du --list-tests json. En befintlig VSTest-klient finns i Programmatisk testidentifiering och körning.
Starta den offentliga JSON-RPC-servern med --server eller --server jsonrpc.
Important
.NET SDK använder ett separat internt binärt protokoll via --server dotnettestcli. Skicka inte med det värdet på egen hand.
dotnet test konfigurerar argumenten för transport och protokoll.
Använd endast källklienten
MTP 2.4 tillhandahåller en kanonisk JSON-RPC-klient. Lägg till Microsoft. Testing.Platform.ServerMode.Client.Sources-paketet. Paketet matar in C#-källan i projektet i stället för att lägga till en runtime-sammansättning.
Designen med endast källkod ger:
- Ingen runtime-DLL eller ytterligare distributionsberoenden.
- Inbyggd AOT-kompatibel, reflektionsfri serialisering.
- Protokolltyper och serialiseringskod från samma lagringsplats som MTP-servern.
De injekterade typerna MtpServerClient, IMtpServerClient och protokoll kan initiera en anslutning, upptäcka tester, köra tester, begära att servern avslutas och rapportera uppdateringar om testnoder. Alla injicerade typer förblir internal för den konsumerande assemblyn. Klienten hanterar processstart, transport, meddelandeinramning och serialisering; du behöver inte implementera JSON-RPC själv.
Paketet kompilerar C#-källa. Om du vill använda klienten från Visual Basic eller ett annat .NET-språk lägger du till en referens till ett C#-klassbibliotek som exponerar ett eget offentligt API kring de injicerade typerna, som i följande exempel.
Upptäck och kör tester från .NET
Det här exemplet använder källkodsendast-versionen 2.5.2 av klientpaketet och är avsett för .NET 10. Skapa först ett MTP-aktiverat testprogram och skicka sedan sökvägen till dess genererade .dll eller körbara programfil till klienten.
Den delade C#-hjälpen identifierar tester, skriver ut varje nods serialiserbara metadata och kör de identifierade testerna med UID. Om du vill köra en delmängd, väljer du de UID:er du behöver från uppdateringarna för identifiering och skickar endast dessa UID:er till RunTestsAsync. Använd inte visningsnamn som testidentiteter.
using System.Text.Json;
using Microsoft.Testing.Platform.ServerMode.Client;
namespace TestClientSample;
public static class TestClient
{
public static async Task<int> DiscoverAndRunAsync(
string testApplicationPath,
CancellationToken cancellationToken = default)
{
string path = Path.GetFullPath(testApplicationPath);
var testUids = new HashSet<string>(StringComparer.Ordinal);
using (IMtpServerClient client = await MtpServerClient.LaunchAsync(
path, cancellationToken: cancellationToken))
{
try
{
MtpServerCapabilities capabilities =
await client.InitializeAsync(cancellationToken);
if (capabilities.MultiConnectionProvider)
{
throw new NotSupportedException("A passive controller connection can't discover or run tests.");
}
if (!capabilities.SupportsDiscovery)
{
throw new NotSupportedException("The test application doesn't support discovery.");
}
client.LogReceived += (_, log) => Console.Error.WriteLine(log.Message);
client.TestNodesUpdated += (_, update) =>
{
foreach (MtpTestNodeUpdate change in update.Changes)
{
Console.WriteLine(JsonSerializer.Serialize(change.Node));
if (change.NodeType != "group"
&& change.ExecutionState == "discovered"
&& change.Uid is string uid)
{
testUids.Add(uid);
}
}
};
await client.DiscoverTestsAsync(cancellationToken);
await client.ExitAsync(cancellationToken);
}
finally
{
await client.ShutdownAsync();
}
}
if (testUids.Count == 0)
{
Console.Error.WriteLine("No tests were discovered.");
return 8;
}
var completedUids = new HashSet<string>(StringComparer.Ordinal);
bool hasUnsuccessfulResult = false;
using IMtpServerClient runClient = await MtpServerClient.LaunchAsync(
path, cancellationToken: cancellationToken);
try
{
MtpServerCapabilities capabilities =
await runClient.InitializeAsync(cancellationToken);
if (capabilities.MultiConnectionProvider)
{
throw new NotSupportedException("A passive controller connection can't discover or run tests.");
}
runClient.LogReceived += (_, log) => Console.Error.WriteLine(log.Message);
runClient.TestNodesUpdated += (_, update) =>
{
foreach (MtpTestNodeUpdate change in update.Changes)
{
Console.WriteLine(JsonSerializer.Serialize(change.Node));
if (change.Uid is string uid
&& testUids.Contains(uid)
&& change.ExecutionState is string state
&& state is not ("discovered" or "in-progress")
&& (!change.Node.TryGetValue("retry.is-superseded", out object? superseded)
|| superseded is not true))
{
completedUids.Add(uid);
hasUnsuccessfulResult |= state is not ("passed" or "skipped");
}
}
};
MtpRunResult result = await runClient.RunTestsAsync(testUids, cancellationToken);
foreach (MtpAttachment artifact in result.Artifacts)
{
Console.WriteLine($"Artifact: {artifact.Uri}");
}
await runClient.ExitAsync(cancellationToken);
if (hasUnsuccessfulResult || !testUids.All(completedUids.Contains))
{
Console.Error.WriteLine("A selected test failed or didn't report a final result.");
return 2;
}
return 0;
}
finally
{
await runClient.ShutdownAsync();
}
}
}
Hjälpprogrammet startar en separat testprocess för upptäckt och körning, så det inte kräver MtpServerCapabilities.MultiRequestSupport. Om du vill återanvända en process, kontrollerar du den kapaciteten efter InitializeAsync innan du skickar flera begäranden. Kontrollera SupportsDiscovery också innan du begär upptäckt.
Important
Källklientens starthjälpfunktioner hanterar en JSON-RPC-anslutning. I version 2.5.2 accepteras och dirigeras inte de ytterligare anslutningarna som används av styrenhetsstödda tillägg. TRX-rapportering i Windows kan till exempel starta en kontroller vars passiva anslutning anländer före den aktiva testvärden. En anslutning med MultiConnectionProvider inställt på true skickar bara uppdateringar och artefakter; skicka inte upptäckts- eller körningsbegäranden till den. Exemplet visar att anslutningen avvisas.
För kontrollbaserade rapporter kör du testapplikationen via CLI eller dotnet test, eller använder ett klientverktyg som hanterar protokollets ytterligare anslutningar. En klient med en enda anslutning kan fortfarande ta emot artefakter som den aktiva testvärden publicerar.
Både C#- och Visual Basic-konsolprojekten refererar till C#-hjälpprojektet:
using TestClientSample;
if (args.Length != 1)
{
Console.Error.WriteLine("Usage: DiscoverAndRun <test-application-path>");
return 1;
}
return await TestClient.DiscoverAndRunAsync(args[0]);
Kör endera av de två konsolprojekten med testprogramsökvägen som argument:
dotnet run --project <client-project> -- <test-application-path>
Exemplet ger 0 när varje valt UID har ett slutligt utfall och varje ej ersatt slutresultat rapporteras som passed eller skipped, 2 för misslyckade eller saknade slutliga utfall, och 8 när upptäckten inte returnerar några tester. Dessa beslut hör till exempelklienten. En slutförd RunTestsAsync uppgift innebär att protokollbegäran slutfördes, inte att testerna klarades.
MtpRunResult.Artifacts innehåller körningsartefakter, inte ett godkänt/underkänt-avgörande. Använd testnodsuppdateringar för att avgöra testresultat.
Flera resultat kan dela ett UID. Exemplet ignorerar endast ett tidigare återförsök när retry.is-superseded är true; enbart UID-likhet innebär inte i sig att det rör sig om ett återförsök. Ett senare godkänt eller överhoppat resultat kan inte upphäva ett tidigare fel som inte har ersatts.
Konsumera uppdateringar och metadata
Prenumerera på TestNodesUpdated innan upptäckt eller körning. Läs Changes från varje uppdatering, och identifiera noder med Uid. Klienten tillhandahåller hjälpegenskaper som DisplayName, ExecutionState, ErrorMessage och DurationInMilliseconds. Läs i Node ordlistan om andra serialiserade fält, inklusive traits och ramverksspecifika egenskaper.
MSTest publicerar testkategorier och anpassade TestProperty värden som traits. Metadatatillgänglighet beror på testramverket och vad det publicerar under identifiering. Godtyckliga attribut och implementeringar av IProperty i minnet passerar inte automatiskt processgränsen. För att publicera portabla metadata med nyckel/värde-par använder du den offentliga typen TestMetadataProperty. Plattformen och kompatibilitetslagren kan tillföra andra serialiserbara fält; deras interna egenskapstyper är inte tilläggs-API:er. Mer information finns i Egenskaper för testnoder.
Förvänta dig inte att JSON-RPC-nodens ordlista matchar --list-tests json dokumentet. Transporterna använder olika fältlayouter. Anta inte heller att alla ramverk genererar de VSTest-specifika vstest.*-fälten.
klienten bearbetar uppdateringarna i tur och ordning och anropar motsvarande hanterare innan identifieringsaktiviteten eller körningsaktiviteten slutförs. Du behöver inte vänta på den slutliga uppdateringen. Hanterare körs synkront på klientens läsloop, så blockera dem inte eller vänta synkront på en annan klientåtgärd. Schemalägg dyra arbets- eller användargränssnittsuppdateringar till lämplig tråd.
Skicka en annulleringstoken till upptäckts- eller körningsmetoder för att begära annullering via protokollet. Om testramverket stöder trädfilter använder du DiscoverTestsWithFilterAsync eller RunTestsWithFilterAsync med ett MTP-trädfilteruttryck för att välja tester utan att först skapa en UID-samling. Dessa metoder accepterar inte VSTest---filteruttryck.
Uppfylla klientkraven
Använd C# 12 eller senare. Paketet respekterar projektets språkversionsinställning. Om ditt målramverk som standard använder en tidigare C#-version anger du LangVersion som 12.0 eller senare. Paketet tillhandahåller även interna kompatibilitetstyper för .NET Framework 4.6.2 och netstandard2.0.
Ta bort en handskriven kopia av MTP-klienten innan du lägger till paketet för att undvika dubbletter av interna typer.
Välj en startmodell
Om du vill starta testprogrammet som en extern process använder du MtpServerClient.LaunchAsync. Klienten äger underprocessen och avslutar den vid behov under nedmonteringen.
Om du vill konfigurera ett externt testprogram för en viss miljö anger du MtpServerClientOptions.EnvironmentVariables före start. Den underordnade processen ärver föräldraprocessens miljö, med de angivna värdena som tillämpas på den underordnade processen. De här alternativen ändrar inte miljön för en värd i processen.
Varje kund styr en testapplikation. För flera testprogram skapar du en klient för varje program och aggregerar deras resultat i verktyget.
För en inbäddad värd- eller UI-trådmiljö som inte kan använda Process.Startanvänder du MtpServerClient.LaunchInProcessAsync. Metoden kör testprogrammet via ett asynkront återanrop i den nuvarande processen. Blockera inte starttråden eftersom återanropet och klienten delar processen.
Båda startmodellerna använder en loopback TCP-transport. Browser WebAssembly kan inte skapa den lyssnare som krävs, så in-processstarten genererar PlatformNotSupportedException. In-process-start ger ingen alternativ WebAssembly-transport.
Stäng av klienten
Om du vill ta bort klienten och starta programmet utan att blockera den anropande tråden anropar du IMtpServerClient.ShutdownAsync(). Den asynkrona metoden undviker UI-trådens svarstider och dödlägesproblem i inbäddade värdar.
För en värd i processen styr MtpServerClientOptions.ServerShutdownTimeout hur länge nedmonteringen väntar efter att klienten har stängt transporten. Standardvärdet är 30 sekunder. Läs ServerExitCode efter avstängningen för att hämta återanropets slutkod. Värdet kvarstår null när programmet körs eller när programmet misslyckas i stället för att returnera en slutkod.
Deklarera tillståndsbevarande klient
Från och med MTP 2.4.1 anger du det nullbara MtpServerClientOptions.IsStateful alternativet för att beskriva hur klienten tar emot uppdateringar för testnoder:
| Value | Deklaration |
|---|---|
true |
Klienten behåller en adresserbar uppsättning testnoder för sessionen och behåller varje nods senaste kända tillstånd tills en annan uppdatering ändrar det, såsom en IDE:s testutforskare kan göra. |
false |
Klienten tar emot uppdateringar utan att behålla testnodtillståndet. |
null (standardinställning) |
Klienten deklarerar inte kapaciteten. Initieringshandskakningen utelämnar fältet. |
Klienten skickar ett explicit booleskt värde via det experimentella capabilities.testing.isStateful protokollstödet. Tillståndsfullhet är oberoende av anslutningens livslängd och serverns MultiRequestSupport kapacitet. En klient blir inte tillståndsbevarande bara för att den skickar flera begäranden via samma anslutning.
MTP 2.4.0 använder ett icke-nullbart booleskt alternativ med standardvärdet false. Om du vill bevara en odeklarerad kapacitet använder du MTP 2.4.1 eller senare.
I ett ramverk eller tillägg använder du den experimentella IClientInfo tjänsten för att inspektera deklarationen. Läs clientInfo.Capabilities.IsStateful för ett konservativt booleskt resultat, vilket är false när kapaciteten är odeklarerad. I MTP 2.4.1 eller senare bevarar ClientCapabilitiesExtensions.GetIsStateful() skillnaden mellan odeklarerade, explicit tillståndslösa och tillståndsfulla klienter.
Förhandla om protokollkompatibilitet
Från och med MTP 2.4 är protokollförhandling i serverläge oberoende av MTP NuGet-paketversionen. En klient deklarerar de protokollversioner som den stöder och servern väljer en gemensam version. När ingen version som stöds överlappar avslutas testprogrammet med ProtocolError slutkoden (12) i stället för att fortsätta med ett inkompatibelt trådkontrakt.
Använd JSON-schemat i versionsläge 1.0 för att verifiera meddelanden. System.Text.Json- och Jsonite-serialiserare följer samma schema och felkuvert.