Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
A plataforma de teste oferece serviços valiosos para a estrutura de teste e pontos de extensão. Esses serviços atendem a necessidades comuns, como aceder à configuração, analisar e recuperar argumentos de linha de comando, obter a fábrica de registos e aceder ao sistema de registos, entre outros.
IServiceProvider aplica o padrão do localizador de serviços para a plataforma de teste.
O IServiceProvider é derivado diretamente da biblioteca de classes base.
namespace System
{
public interface IServiceProvider
{
object? GetService(Type serviceType);
}
}
A plataforma de testes oferece métodos úteis de extensão para aceder a objetos de serviço amplamente conhecidos. Todos esses métodos são alojados em uma classe estática dentro do namespace Microsoft.Testing.Platform.Services.
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 maioria das fábricas de registo expostas por pontos de extensão fornece acesso ao IServiceProvider: Por exemplo, ao registar o quadro de testes, o IServiceProvider é passado como parâmetro ao método de fábrica.
ITestApplicationBuilder RegisterTestFramework(
Func<IServiceProvider, ITestFrameworkCapabilities> capabilitiesFactory,
Func<ITestFrameworkCapabilities, IServiceProvider, ITestFramework> adapterFactory);
No código anterior, tanto o capabilitiesFactory quanto o adapterFactory fornecem o IServiceProvider como parâmetro.
A partir do MTP 2.5, use GetRequiredPlatformService<TService>() ou GetPlatformService<TService>() quando o seu projeto também importa Microsoft.Extensions.DependencyInjection. Estes nomes evitam ambiguidades relativamente aos métodos de extensão GetRequiredService e GetService do pacote de injeção de dependências. O método de serviço requerido lança uma exceção quando o serviço de plataforma está ausente; o método de serviço opcional devolve null.
O serviço IConfiguration
A interface IConfiguration pode ser recuperada usando o IServiceProvider e fornece acesso às definições de configuração da estrutura de testes e a quaisquer pontos de extensão. Por padrão, essas configurações são carregadas de:
- Opções de linha de comandos, expostas sob a
commandLineOptions:secção. - Variáveis de ambiente.
- Um ficheiro JSON chamado [appname].testconfig.json localizado ao lado do executável da aplicação de teste.
As opções de linha de comandos têm precedência sobre as variáveis de ambiente, que têm precedência sobre valores de [appname].testconfig.json. O MTP carrega todas as fontes e seleciona a primeira fonte que fornece cada chave. Para valores commandLineOptions: , o MTP seleciona uma fonte para a opção completa para que os argumentos indexados não se combinem entre fontes. Para detalhes sobre a descoberta e precedência dos ficheiros de configuração, consulte as definições de configuração do MTP.
A interface é um par de cadeias de caracteres chave-valor simples:
public interface IConfiguration
{
string? this[string key] { get; }
}
A partir do MTP 2.4.0, o serviço de configuração também implementa a IConfigurationRoot interface. Utilize GetSection para obter um IConfigurationSection, e utilize GetChildren para enumerar secções filhas imediatas. Uma secção expõe o seu Key, o estado completo Path, o estado escalar opcional Value e o estado HasValue. Os provedores têm de implementar IHierarchicalConfigurationProvider antes de as suas chaves aparecerem na enumeração, mas é possível obter um caminho já conhecido de qualquer provedor.
Arquivo de configuração JSON
O arquivo JSON segue uma estrutura hierárquica. Para aceder a propriedades filhas, precisa de usar o separador :. Por exemplo, considere uma configuração para uma estrutura de teste potencial como:
{
"CustomTestingFramework": {
"DisableParallelism": true
}
}
O trecho de código teria a seguinte aparência:
IServiceProvider serviceProvider = null; // Get the service provider...
var configuration = serviceProvider.GetConfiguration();
if (bool.TryParse(configuration["CustomTestingFramework:DisableParallelism"], out var value) && value is true)
{
// ...
}
No caso de uma matriz, como:
{
"CustomTestingFramework": {
"Engine": [
"ThreadPool",
"CustomThread"
]
}
}
A sintaxe para acesso ao primeiro elemento ("ThreadPool") é:
IServiceProvider serviceProvider = null; // Get the service provider...
var configuration = serviceProvider.GetConfiguration();
var fistElement = configuration["CustomTestingFramework:Engine:0"];
Variáveis de ambiente
O separador : não funciona com chaves hierárquicas de variáveis de ambiente em todas as plataformas.
__, o sublinhado duplo, é:
- Suportado por todas as plataformas. Por exemplo, o separador
:não é suportado pelo Bash, mas__é. - Substituído automaticamente por um
:
Por exemplo, a variável de ambiente pode ser definida da seguinte forma (Este exemplo é aplicável para Windows):
setx CustomTestingFramework__DisableParallelism=True
Você pode optar por não usar a fonte de configuração da variável de ambiente ao criar o ITestApplicationBuilder:
var options = new TestApplicationOptions();
options.Configuration.ConfigurationSources.RegisterEnvironmentVariablesConfigurationSource = false;
var builder = await TestApplication.CreateBuilderAsync(args, options);
O serviço ICommandLineOptions
O serviço ICommandLineOptions é utilizado para buscar detalhes sobre as opções de linha de comando que a plataforma analisou. As APIs disponíveis incluem:
public interface ICommandLineOptions
{
bool IsOptionSet(string optionName);
bool TryGetOptionArgumentList(
string optionName,
out string[]? arguments);
}
O ICommandLineOptions pode ser obtido por meio de determinadas APIs, como o ICommandLineOptionsProvider, ou você pode recuperar uma instância dele do IServiceProvider por meio do método de extensão serviceProvider.GetCommandLineOptions().
ICommandLineOptions.IsOptionSet(string optionName): Este método permite verificar se uma opção específica foi especificada. Ao especificar o optionName, omita o prefixo --. Por exemplo, se o usuário inserir --myOption, você deve simplesmente passar myOption.
ICommandLineOptions.TryGetOptionArgumentList(string optionName, out string[]? arguments): Este método permite verificar se uma opção específica foi definida e, em caso afirmativo, recuperar o valor ou valores correspondentes (se a aridade for mais do que um). Semelhante ao caso anterior, o optionName deve ser fornecido sem o prefixo --.
O serviço IArtifactNamingService
A partir do MTP 2.4.0, IArtifactNamingService dá às extensões o mesmo templamento de nomes de ficheiro multiplataforma que as extensões de relatório MTP usam. Obtém-no com serviceProvider.GetArtifactNamingService() e depois chama ResolveFileName com um modelo.
O serviço expande {pname}, {pid}, {asm}, {tfm}, {arch} e {time}. Mantém os segmentos de diretórios e saneia o nome do ficheiro final para o sistema operativo atual. Os marcadores desconhecidos mantêm-se inalterados. Para descrições provisórias, consulte Nomes dos ficheiros de relatório.
O serviço ILoggerFactory
A plataforma de teste vem com um sistema de registro integrado que gera um arquivo de log. Você pode exibir as opções de registro executando o comando --help.
As opções que você pode escolher incluem:
--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'
Do ponto de vista da codificação, para registar informações, é necessário obter o ILoggerFactory do IServiceProvider.
A API ILoggerFactory é a seguinte:
public interface ILoggerFactory
{
ILogger CreateLogger(string categoryName);
}
public static class LoggerFactoryExtensions
{
public static ILogger<TCategoryName> CreateLogger<TCategoryName>(this ILoggerFactory factory);
}
A fábrica de logs permite que tu cries um objeto ILogger usando a API CreateLogger. Há também uma API conveniente que aceita um argumento genérico, que será usado como o nome da categoria.
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);
}
O objeto ILogger, que é criado pelo ILoggerFactory, oferece APIs para registrar informações em vários níveis. Estes níveis de registo incluem:
public enum LogLevel
{
Trace,
Debug,
Information,
Warning,
Error,
Critical,
None,
}
Aqui está um exemplo de como você pode usar a API de registro:
...
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}'");
}
// ...
Lembre-se de que, para evitar alocações desnecessárias, você deve verificar se o nível está habilitado usando a API ILogger.IsEnabled(LogLevel).
O serviço IDiagnosticLoggingInformation
A partir da versão de pré-visualização do MTP 2.5, chame serviceProvider.GetDiagnosticLoggingInformation() para obter informações experimentais sobre o registador de ficheiros de diagnóstico incorporado. O método retorna null quando o registo de diagnóstico não está ativado.
O IDiagnosticLoggingInformation serviço expõe:
-
LogFile, o ficheiro que atualmente recebe entradas de diagnóstico. -
LogLevel, o nível mínimo escrito no ficheiro. -
SynchronousWrite, que indica se o registrador de ficheiros escreve entradas de forma síncrona.
O serviço está ativo. Durante a construção da aplicação de teste, o MTP pode mover o ficheiro de registo para o diretório efetivo dos resultados. Mantém o serviço e lê LogFile quando precisares do caminho em vez de guardares em cache o primeiro FileInfo. Se a recuperação do registo deixar um ficheiro parcial na localização original, LogFile identifica o ficheiro de substituição que recebe novas entradas.
Importante
Esta API utiliza o TPEXP ID de diagnóstico e pode ser alterada ou removida numa versão futura.
O serviço IMessageBus
O serviço de barramento de mensagens é o mecanismo central que facilita a troca de informação entre a estrutura de teste e as suas extensões.
O barramento de mensagens da plataforma de teste emprega o padrão publicação-assinatura.
A estrutura geral do barramento compartilhado é a seguinte:
Como ilustrado no diagrama, que inclui uma extensão e uma estrutura de teste, existem duas ações possíveis: transferir informações para o barramento ou receber informações do barramento.
O IMessageBus completou a ação de empurrar do para o barramento e a API é:
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; }
}
Considere os seguintes detalhes sobre os parâmetros:
IDataProducer: OIDataProducercomunica ao barramento de mensagens oTypede informação que pode fornecer e estabelece a propriedade através da herança da interface base IExtension. Isso implica que você não pode enviar dados indiscriminadamente para o barramento de mensagens; Você deve declarar o tipo de dados produzidos antecipadamente. Se você enviar dados inesperados, uma exceção será acionada.IData: Esta interface serve como um espaço reservado onde você só precisa fornecer detalhes descritivos, como o nome e uma descrição. A interface não revela muito sobre a natureza dos dados, que é intencional. Isso implica que o framework de teste e as extensões podem enviar qualquer tipo de dados para o barramento, e esses dados podem ser consumidos por qualquer extensão registada ou pelo próprio framework de teste.
Esta abordagem facilita a evolução do processo de troca de informações, evitando alterações inesperadas quando uma extensão não está familiarizada com novos dados. Permite que diferentes versões de extensões e a estrutura de teste operem em harmonia, com base em sua compreensão mútua.
A extremidade oposta do barramento é designada por consumidor, que está subscrito a um tipo específico de dados e pode assim consumi-los.
Importante
Utilize sempre aguarde a chamada para PublishAsync. Se você não fizer isso, o IData pode não ser processado corretamente pela plataforma de teste e extensões, o que pode levar a bugs sutis. Só depois de regressar do aguardar é que pode ter a certeza de que o IData foi colocado na fila para processamento no barramento de mensagens. Independentemente do ponto de extensão em que está a trabalhar, certifique-se de ter aguardado por todas as chamadas PublishAsync antes de sair da extensão. Por exemplo, se estiveres a implementar o testing framework, não deverás chamar Complete nos pedidos até teres aguardado todas as chamadas PublishAsync para esse pedido específico.
O serviço ITestCoverageCapabilities
A partir do MTP 2.4, recupere ITestCoverageCapabilities de IServiceProvider para descobrir se há suporte para mensagens de cobertura. O serviço expõe:
-
SupportsTestCoverageMessages, que indica suporte ao contrato de mensagens de cobertura da plataforma. -
EnabledProducerUids, um instantâneo de UIDs de produtor ativados que declaram pelo menos um deTestCoverageMessage,TestCoverageThresholdMessage, ouTestCoverageReportMessage.
Leia a lista de produtores a partir de um callback do ciclo de vida da sessão após a construção da extensão, não de uma fábrica de registo ou construtor. Um produtor habilitado declara apoio; a lista não garante que o produtor já tenha publicado as medições. Uma lista vazia não significa que a plataforma não tenha suporte a mensagens de cobertura.
No MTP 2.5 ou posterior, recupere o serviço com serviceProvider.GetRequiredPlatformService<ITestCoverageCapabilities>(). No MTP 2.4, use GetRequiredService<ITestCoverageCapabilities>() de Microsoft.Testing.Platform.Services.
Para um exemplo de produtor e consumidor executável, consulte Publish coverage results.
O serviço ITestCoverageResult
A partir do MTP 2.4, ITestCoverageResult fornece os dados de cobertura correlacionados da plataforma. Recupere o serviço de IServiceProvider e utilize os seguintes membros:
| Membro | Purpose |
|---|---|
GetOverall(sessionUid) |
Retorna o resumo geral reportado da sessão, ou null se não existir. |
Scopes |
Retorna CoverageScopeSummary registos com a sua sessão, âmbito e métricas. |
Thresholds |
Retorna as avaliações limiares reportadas, incluindo avaliações aprovadas e falhadas. |
Reports |
Devolve referências de relatórios de cobertura, os respetivos formatos e IDs de produtores. |
HasThresholdFailure |
Indica se algum limiar reportado falhou. |
A chave de correlação de uma medição inclui a sessão, o produtor, o âmbito, a métrica e o nome da métrica personalizada, quando aplicável. Uma medição posterior com a mesma chave substitui o valor anterior; O MTP não soma mensagens duplicadas. Diferentes produtores permanecem separados mesmo quando apresentam a mesma métrica e âmbito.
CoverageScopeSummary.Metrics preserva de cada ProducerIdmétrica. O indexador abreviado, como summary[CoverageMetric.Line], devolve o resultado do primeiro produtor correspondente. Para selecionar um coletor específico, inspecione Metrics e compare ProducerId. Utilize GetCustom(name) para métricas personalizadas em vez do indexador.
Um resumo ausente significa que não foi reportada nenhuma medição correspondente. Um resultado com HasCoverableData definido para false significa que o coletor reportou zero unidades cobertíveis. Não substitua nenhum dos casos por um resultado de 100% bem-sucedido.
Como o barramento de mensagens processa dados de forma assíncrona, não consulte o serviço imediatamente após PublishAsync e assuma que a nova mensagem está presente. Para um resultado de fim de execução, leia após o término da sessão, tal como o exemplo de cobertura faz em ITestHostApplicationLifetime.AfterRunAsync.
O serviço IClientInfo
Para identificar o cliente que controla uma aplicação de teste, chame serviceProvider.GetClientInfo() enquanto um pedido ou sessão de teste está ativa. No modo servidor, o handshake de inicialização estabelece esta informação. O serviço experimental IClientInfo expõe Id, Version, e Capabilities. A partir do MTP 2.4, Capabilities fornece um valor IClientCapabilities que reflete o carácter de manutenção de estado declarado pelo cliente.
Um cliente com estado mantém um conjunto endereçável de nós de teste para a sessão e mantém o último estado conhecido de cada nó até que uma atualização o substitua. Um cliente sem estado consome atualizações sem reter esse estado. A distinção não descreve a duração da ligação nem se o servidor aceita múltiplos pedidos.
Utilize clientInfo.Capabilities.IsStateful para um resultado booleano conservador: uma capacidade não declarada devolve false. Para distinguir uma capacidade explícita false de uma não declarada, use ClientCapabilitiesExtensions.GetIsStateful() no MTP 2.4.1 ou posterior:
| Result | Meaning |
|---|---|
true |
O cliente declara explicitamente o estado do nó de teste retido. |
false |
O cliente declara explicitamente o comportamento sem estado. |
null |
O serviço fornecido pela plataforma não tem nenhuma declaração do cliente. |
Para uma implementação personalizada IClientCapabilities , GetIsStateful() devolve o seu IsStateful valor. Para declarar a funcionalidade a partir de um editor ou ferramenta, veja Declarar estado do cliente.
Importante
IClientInfo, IClientCapabilities, ClientCapabilitiesExtensions e TPEXP são experimentais e utilizam o ID de diagnóstico GetClientInfo. A presença deles num pacote MTP estável não torna as APIs estáveis.
O serviço IOutputDevice
A plataforma de teste encapsula a ideia de um dispositivo de saída , permitindo que a estrutura de teste e as extensões apresentem informações, transmitindo qualquer tipo de dados para o sistema de exibição atualmente utilizado.
O exemplo mais tradicional de um dispositivo de saída é a saída do console.
Observação
Embora a plataforma de teste seja projetada para suportar dispositivos de saída personalizados, atualmente, esse ponto de extensão não está disponível.
Para transmitir dados para o dispositivo de saída , você deve obter o IOutputDevice do IServiceProvider.
A API consiste em:
public interface IOutputDevice
{
Task DisplayAsync(
IOutputDeviceDataProducer producer,
IOutputDeviceData data,
CancellationToken cancellationToken);
}
public interface IOutputDeviceDataProducer : IExtension
{
}
public interface IOutputDeviceData
{
}
O IOutputDeviceDataProducer estende o IExtension e fornece informações sobre o remetente para o dispositivo de saída .
O IOutputDeviceData serve como uma interface de espaço reservado. O conceito por trás IOutputDevice é acomodar informações mais complexas do que apenas texto colorido. Por exemplo, pode ser um objeto complexo que pode ser representado graficamente.
A plataforma de teste, por padrão, oferece um modelo de texto colorido tradicional para o objeto IOutputDeviceData:
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; }
}
Aqui está um exemplo de como você pode usar o texto colorido no dispositivo de saída ativo:
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);
Além do uso padrão de texto colorido, a principal vantagem de IOutputDevice e IOutputDeviceData é que o dispositivo de saída é totalmente independente e desconhecido para o usuário. Isso permite o desenvolvimento de interfaces de usuário complexas. Por exemplo, é perfeitamente possível implementar uma aplicação web em tempo real que exiba o progresso dos testes.
O serviço IPlatformInformation
O serviço experimental IPlatformInformation disponibiliza a plataforma Name, bem como Version, CommitHash e BuildDate opcionais.