Microsoft.Testing.Platform-szolgáltatások

A tesztelési platform értékes szolgáltatásokat kínál mind a tesztelési keretrendszer, mind a bővítménypontok számára. Ezek a szolgáltatások olyan gyakori igényeket is kielégítenek, mint például a konfiguráció elérése, parancssori argumentumok elemzése és lekérése, a naplózási előállító beszerzése és a naplózási rendszer elérése. IServiceProvider implementálja a szolgáltatáskereső mintáját a tesztelési platformhoz.

A IServiceProvider közvetlenül az alaposztálytárból származik.

namespace System
{
    public interface IServiceProvider
    {
        object? GetService(Type serviceType);
    }
}

A tesztelési platform hasznos bővítési metódusokat kínál a közismert szolgáltatási objektumok eléréséhez. Ezek a metódusok egy statikus osztályban találhatók a Microsoft.Testing.Platform.Services névtérben.

public static class ServiceProviderExtensions
{
    public static TService GetRequiredService<TService>(
        this IServiceProvider provider)

    public static TService? GetService<TService>(
        this IServiceProvider provider)

    public static IMessageBus GetMessageBus(
        this IServiceProvider serviceProvider)

    public static IConfiguration GetConfiguration(
        this IServiceProvider serviceProvider)

    public static ICommandLineOptions GetCommandLineOptions(
        this IServiceProvider serviceProvider)

    public static ILoggerFactory GetLoggerFactory(
        this IServiceProvider serviceProvider)

    public static IOutputDevice GetOutputDevice(
        this IServiceProvider serviceProvider)

    // ... and more
}

A bővítménypontok által közzétett regisztrációs gyárak többsége hozzáférést biztosít a IServiceProvider számára: Például, amikor a tesztelési keretrendszer regisztrálása történik, a IServiceProvider paraméterként van átadva a gyári metódusnak.

ITestApplicationBuilder RegisterTestFramework(
    Func<IServiceProvider, ITestFrameworkCapabilities> capabilitiesFactory,
    Func<ITestFrameworkCapabilities, IServiceProvider, ITestFramework> adapterFactory);

Az előző kódban a capabilitiesFactory és a adapterFactory is paraméterként adja meg a IServiceProvider.

A IConfiguration szolgáltatás

A IConfiguration interfész a IServiceProvider használatával kérhető le, és access biztosít a tesztelési keretrendszer és a bővítménypontok konfigurációs beállításaihoz. Alapértelmezés szerint ezek a konfigurációk a következőkből töltődnek be:

  • A(z) commandLineOptions: szakaszban elérhető parancssori beállítások.
  • Környezeti változók.
  • A [appname].testconfig.json nevű JSON-fájl, amely a tesztalkalmazás végrehajtható fájlja mellett található.

A parancssori kapcsolók elsőbbséget élveznek a környezeti változókkal szemben, amelyek viszont elsőbbséget élveznek a(z) [appname].testconfig.json fájl értékeivel szemben. Az MTP betölti az összes forrást, és kiválasztja az egyes kulcsokat ellátó első forrást. Értékek esetén commandLineOptions: az MTP kiválaszt egy forrást a teljes beállításhoz, így az indexelt argumentumok nem egyesíthetők a források között. A konfigurációs fájlok felderítéséről és az elsőbbségről az MTP konfigurációs beállításaiban talál további információt.

Az interfész egy egyszerű kulcs-érték karakterláncpár.

public interface IConfiguration
{
    string? this[string key] { get; }
}

Az MTP 2.4.0-tól kezdve a konfigurációs IConfigurationRoot szolgáltatás a felületet is implementálja. A GetSection lekéréséhez használja a(z) IConfigurationSection elemet, a közvetlen alszakaszok felsorolásához pedig a(z) GetChildren elemet. Egy szakasz elérhetővé teszi a saját Key, a teljes Path, az opcionális skalár Value és a HasValue állapotát. A szolgáltatóknak implementálniuk kell a IHierarchicalConfigurationProvider elemet, mielőtt a kulcsaik megjelennek az enumerálás során, de ismert elérési utat bármely szolgáltatótól lekérdezhet.

JSON-konfigurációs fájl

A JSON-fájl hierarchikus struktúrát követ. A gyermektulajdonságok eléréséhez a : elválasztót kell használnia. Vegyünk például egy konfigurációt egy lehetséges tesztelési keretrendszerhez, például:

{
  "CustomTestingFramework": {
    "DisableParallelism": true
  }
}

A kódrészlet a következőképpen nézne ki:

IServiceProvider serviceProvider = null; // Get the service provider...

var configuration = serviceProvider.GetConfiguration();

if (bool.TryParse(configuration["CustomTestingFramework:DisableParallelism"], out var value) && value is true)
{
    // ...
}

Például egy tömb esetén:

{
  "CustomTestingFramework": {
    "Engine": [
      "ThreadPool",
      "CustomThread"
    ]
  }
}

Az első elem ("ThreadPool") elérési szintaxisa a következő:

IServiceProvider serviceProvider = null; // Get the service provider...

var configuration = serviceProvider.GetConfiguration();

var fistElement = configuration["CustomTestingFramework:Engine:0"];

Környezeti változók

A : elválasztó nem működik a környezeti változók hierarchikus kulcsaival minden platformon. __, a dupla aláhúzásjel a következő:

  • Minden platform támogatja. A : elválasztójelet például nem támogatja Bash, de __ igen.
  • Automatikusan lecserélve egy :-ra

A környezeti változó például a következőképpen állítható be (Ez a példa Windows esetén alkalmazható):

setx CustomTestingFramework__DisableParallelism=True

Dönthet úgy, hogy nem használja a környezeti változó konfigurációs forrását a ITestApplicationBuilderlétrehozásakor:

var options = new TestApplicationOptions();

options.Configuration.ConfigurationSources.RegisterEnvironmentVariablesConfigurationSource = false;

var builder = await TestApplication.CreateBuilderAsync(args, options);

A ICommandLineOptions szolgáltatás

A ICommandLineOptions szolgáltatás a platform által elemezett parancssori beállítások részleteinek lekérésére szolgál. Az elérhető API-k a következők:

public interface ICommandLineOptions
{
    bool IsOptionSet(string optionName);

    bool TryGetOptionArgumentList(
        string optionName, 
        out string[]? arguments);
}

A ICommandLineOptions megszerezhető bizonyos API-ken keresztül, mint például az ICommandLineOptionsProvider. Alternatívaként az IServiceProvider egy példányát is lekérheti a serviceProvider.GetCommandLineOptions()bővítménymetódus használatával.

ICommandLineOptions.IsOptionSet(string optionName): Ezzel a módszerrel ellenőrizheti, hogy adott beállítás van-e megadva. A optionNamemegadásakor hagyja ki a -- előtagot. Ha például a felhasználó beírja --myOption, egyszerűen át kell adnia myOption.

ICommandLineOptions.TryGetOptionArgumentList(string optionName, out string[]? arguments): Ezzel a módszerrel ellenőrizheti, hogy egy adott beállítás be van-e állítva, és ha igen, lekérheti a megfelelő értéket vagy értékeket (ha az aritás egynél több). Az előző esethez hasonlóan a optionName a -- előtag nélkül kell megadni.

A IArtifactNamingService szolgáltatás

Az MTP 2.4.0-tól kezdve IArtifactNamingService a bővítmények számára ugyanazt a platformfüggetlen fájlnévsablonozást biztosítja, mint amelyet az MTP jelentésbővítményei használnak. Kérje le a(z) serviceProvider.GetArtifactNamingService() használatával, majd hívja meg a(z) ResolveFileName függvényt egy sablonnal.

A szolgáltatás kibővül {pname}, {pid}, {asm}, {tfm}{arch}és {time}. Megőrzi a címtárszegmenseket, és megtisztítja az aktuális operációs rendszer levélfájlnevét. Az ismeretlen helyőrzők változatlanok maradnak. A helyőrzők leírását lásd a Jelentésfájlnevek című részben.

A ILoggerFactory szolgáltatás

A tesztelési platform egy integrált naplózási rendszerrel rendelkezik, amely létrehoz egy naplófájlt. A naplózási beállításokat a --help parancs futtatásával tekintheti meg. Az alábbi lehetőségek közül választhat:

--diagnostic                             Enable the diagnostic logging. The default log level is 'Trace'. The file will be written in the output directory with the name log_[MMddHHssfff].diag
--diagnostic-synchronous-write Force the built-in file logger to write the log synchronously. Useful for scenario where you don't want to lose any log (i.e. in case of crash). Note that this is slowing down the test execution.
--diagnostic-output-directory            Output directory of the diagnostic logging, if not specified the file will be generated inside the default 'TestResults' directory.
--diagnostic-file-prefix           Prefix for the log file name that will replace '[log]_.'
--diagnostic-verbosity                   Define the level of the verbosity for the --diagnostic. The available values are 'Trace', 'Debug', 'Information', 'Warning', 'Error', and 'Critical'

Kódolási szempontból az információk naplózásához be kell szerezni ILoggerFactory-t a IServiceProvider-ből. A ILoggerFactory API a következő:

public interface ILoggerFactory
{
    ILogger CreateLogger(string categoryName);
}

public static class LoggerFactoryExtensions
{
    public static ILogger<TCategoryName> CreateLogger<TCategoryName>(this ILoggerFactory factory);
}

A logger factory lehetővé teszi egy ILogger objektum létrehozását a CreateLogger API használatával. Van egy kényelmes API is, amely elfogad egy általános argumentumot, amelyet kategórianévként használunk.

public interface ILogger
{
    Task LogAsync<TState>(
        LogLevel logLevel, 
        TState state, 
        Exception? exception, 
        Func<TState, Exception?, string> formatter);

    void Log<TState>(
        LogLevel logLevel,
        TState state, 
        Exception? exception, 
        Func<TState, Exception?, string> formatter);

    bool IsEnabled(LogLevel logLevel);
}

public interface ILogger<out TCategoryName> : ILogger
{
}

public static class LoggingExtensions
{
    public static Task LogCriticalAsync(this ILogger logger, string message);
    public static Task LogDebugAsync(this ILogger logger, string message);
    public static Task LogErrorAsync(this ILogger logger, Exception ex);
    public static Task LogErrorAsync(this ILogger logger, string message, Exception ex);
    public static Task LogErrorAsync(this ILogger logger, string message);
    public static Task LogInformationAsync(this ILogger logger, string message);
    public static Task LogTraceAsync(this ILogger logger, string message);
    public static Task LogWarningAsync(this ILogger logger, string message);
    public static void LogCritical(this ILogger logger, string message);
    public static void LogDebug(this ILogger logger, string message);
    public static void LogError(this ILogger logger, Exception ex);
    public static void LogError(this ILogger logger, string message, Exception ex);
    public static void LogError(this ILogger logger, string message);
    public static void LogInformation(this ILogger logger, string message);
    public static void LogTrace(this ILogger logger, string message);
    public static void LogWarning(this ILogger logger, string message);
}

A ILoggeráltal létrehozott ILoggerFactory objektum API-kat kínál az információk naplózásához különböző szinteken. Ezek a naplózási szintek a következők:

public enum LogLevel
{
    Trace,
    Debug,
    Information,
    Warning,
    Error,
    Critical,
    None,
}

Íme egy példa a naplózási API használatára:

...
IServiceProvider provider = null; // Get the service provider...

var factory = provider.GetLoggerFactory();

var logger = factory.CreateLogger<TestingFramework>();

// ...

if (logger.IsEnabled(LogLevel.Information))
{
    await logger.LogInformationAsync(
        $"Executing request of type '{context.Request}'");
}

// ...

Ne feledje, hogy a szükségtelen lefoglalás elkerülése érdekében ellenőrizze, hogy a szint engedélyezve van-e a ILogger.IsEnabled(LogLevel) API használatával.

A IMessageBus szolgáltatás

A message bus szolgáltatás a központi mechanizmus, amely megkönnyíti a tesztelési keretrendszer és a bővítmények közötti exchange információkat.

A tesztelési platform üzenetbusza a közzétételi-feliratkozási mintát használja.

A megosztott busz átfogó szerkezete a következő:

A különböző bővítmények és az üzenetbusz közötti interakciókat ábrázoló kép.

Ahogy a diagram egy bővítményt és egy tesztelési keretrendszert is tartalmaz, két lehetséges művelet létezik: az információk buszra való leküldése vagy a buszból származó információk felhasználása.

A IMessageBus elvégezte a busz felé történő toló műveletet, és az API a következő:

public interface IMessageBus
{
    Task PublishAsync(
        IDataProducer dataProducer, 
        IData data);
}

public interface IDataProducer : IExtension
{
    Type[] DataTypesProduced { get; }
}

public interface IData
{
    string DisplayName { get; }
    string? Description { get; }
}

Vegye figyelembe a paraméterekkel kapcsolatos alábbi részleteket:

  • IDataProducer: A IDataProducer közli az üzenetbusszal, hogy milyen információkat tud szolgáltatni (Type), és öröklés útján létesít tulajdonjogot a bázis interfész, az IExtension felett. Ez azt jelenti, hogy nem lehet válogatás nélkül leküldni az adatokat az üzenetbuszba; az előre létrehozott adattípust deklarálnia kell. Váratlan adatok leküldése esetén a rendszer kivételt vált ki.

  • IData: Ez az interfész helyőrzőként szolgál, ahol csak leíró adatokat kell megadnia, például a nevet és a leírást. Az interfész nem sokat fed fel az adatok természetéről, ami szándékos. Ez azt jelenti, hogy a tesztelési keretrendszer és a bővítmények bármilyen típusú adatot leküldhetnek a buszra, és ezeket az adatokat bármely regisztrált bővítmény vagy maga a tesztelési keretrendszer felhasználhatja.

Ez a megközelítés megkönnyíti az információcsere folyamatának fejlődését, megakadályozva a kompatibilitást sértő változásokat, ha egy bővítmény nem ismeri az új adatokat. Lehetővé teszi a bővítmények különböző verzióinak és a tesztelési keretrendszernek, hogy harmóniában működjenek, a kölcsönös megértésükalapján.

A busz másik végét consumer néven nevezik, amely egy adott adattípusra van előfizetve, és így felhasználhatja azt.

Fontos

Mindig várjonPublishAsynchívására. Ha nem, előfordulhat, hogy a IData a tesztelési platform és a bővítmények nem megfelelően dolgozzák fel, ami apró hibákhoz vezethet. Csak azután, hogy visszatért a várja, hogy biztos lehet abban, hogy a IData várólistára került az üzenetbuszon való feldolgozás céljából. Függetlenül attól, hogy milyen bővítményponton dolgozik, győződjön meg arról, hogy minden PublishAsync hívás befejeződött, mielőtt kilépne a bővítményből. Ha például ön hajtja végre a testing framework-t, ne hívja meg a Complete-et a kéréseken, amíg nem várta meg az adott kérés összes PublishAsync hívását.

A IOutputDevice szolgáltatás

A tesztelési platform magában foglalja egy kimeneti eszköz fogalmát, amely lehetővé teszi a tesztelési keretrendszer és a bővítmények számára, hogy bármilyen adatot továbbítsanak a jelenleg használt megjelenítési rendszerbe a információk bemutatására.

A kimeneti eszköz legtradícionálisabb példája a konzol kimenete.

Jegyzet

Bár a tesztelési platform úgy van kialakítva, hogy támogassa az egyéni kimeneti eszközöket, ez a bővítmény jelenleg nem érhető el.

Az adatoknak a kimeneti eszköz-hoz történő továbbításához be kell szereznie a IOutputDevice-ból a IServiceProvider-t.

Az API a következőkből áll:

public interface IOutputDevice
{
    Task DisplayAsync(
        IOutputDeviceDataProducer producer,
        IOutputDeviceData data,
        CancellationToken cancellationToken);
}

public interface IOutputDeviceDataProducer : IExtension
{
}

public interface IOutputDeviceData
{
}

A IOutputDeviceDataProducer kibővíti a IExtension-et, és információt nyújt a feladóról a kimeneti eszköz-nak.

A IOutputDeviceData helyettesítő felületként szolgál. A IOutputDevice mögött az a koncepció áll, hogy a színezett szöveg helyett bonyolultabb információkat fogadjon el. Ez lehet például egy összetett objektum, amely grafikusan ábrázolható.

A tesztelési platform alapértelmezés szerint hagyományos színes szövegmodellt kínál a IOutputDeviceData objektumhoz:

public class TextOutputDeviceData : IOutputDeviceData
{
    public TextOutputDeviceData(string text)
    public string Text { get; }
}

public sealed class FormattedTextOutputDeviceData : TextOutputDeviceData
{
    public FormattedTextOutputDeviceData(string text)
    public IColor? ForegroundColor { get; init; }
    public IColor? BackgroundColor { get; init; }
}

public sealed class SystemConsoleColor : IColor
{
    public ConsoleColor ConsoleColor { get; init; }
}

Íme egy példa arra, hogyan használhatja a színes szöveget az aktív kimeneti eszközzel:

IServiceProvider provider = null; // Get the service provider...

var outputDevice = provider.GetOutputDevice();

await outputDevice.DisplayAsync(
    this,
    new FormattedTextOutputDeviceData($"TestingFramework version '{Version}' running tests with parallelism of {_dopValue}")
    {
        ForegroundColor = new SystemConsoleColor
        {
            ConsoleColor = ConsoleColor.Green
        }
    },
    CancellationToken.None);

A színes szövegek szabványos használata mellett a IOutputDevice és a IOutputDeviceData fő előnye, hogy a kimeneti eszköz teljesen független és ismeretlen a felhasználó számára. Ez lehetővé teszi összetett felhasználói felületek fejlesztését. Teljesen megvalósítható például egy valós idejű webalkalmazás implementálása, amely megjeleníti a tesztek előrehaladását.

A IPlatformInformation szolgáltatás

A kísérleti IPlatformInformation szolgáltatás a következőket biztosítja: platform Name, opcionális Version, opcionális CommitHash és opcionális BuildDate.