Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
A plataforma de teste oferece serviços valiosos para a estrutura de teste e os pontos de extensão. Esses serviços atendem a necessidades comuns, como acessar as configurações, analisar e recuperar os argumentos da linha de comando, obter a fábrica de registros e acessar o sistema de registro em log, entre outros.
IServiceProvider implementa o padrão do localizador de serviço 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 teste oferece métodos de extensão úteis para acessar objetos de serviço bem conhecidos. Todos esses métodos são alojados em uma classe estática dentro do Microsoft.Testing.Platform.Services namespace.
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 registro expostas por pontos de extensão fornece acesso ao IServiceProvider: por exemplo, ao registrar a estrutura de teste, o IServiceProvider é passado como um parâmetro para o 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 um parâmetro.
A partir do MTP 2.5, use GetRequiredPlatformService<TService>() ou GetPlatformService<TService>() quando seu projeto também importar Microsoft.Extensions.DependencyInjection. Esses nomes evitam ambiguidade com os métodos de extensão GetService e GetRequiredService do pacote de injeção de dependência. O método de serviço necessário lança uma exceção quando o serviço de plataforma está ausente; o método de serviço opcional retorna null.
O serviço IConfiguration
A interface IConfiguration pode ser recuperada usando o IServiceProvider e fornece acesso às configurações do framework de teste e a todos os pontos de extensão. Por padrão, essas configurações são carregadas de:
- Opções de linha de comando, expostas na
commandLineOptions:seção. - Variáveis de ambiente.
- Um arquivo JSON chamado [appname].testconfig.json localizado ao lado do executável do aplicativo de teste.
As opções de linha de comando têm precedência sobre 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 commandLineOptions: valores, o MTP seleciona uma origem para a opção completa para que os argumentos indexados não se combinem entre fontes. Para obter detalhes sobre a descoberta e a precedência do arquivo de configuração, consulte as configurações 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. Use GetSection para recuperar um IConfigurationSection e GetChildren para enumerar as seções filhas imediatas. Uma seção expõe seu estado Key, completo Path, escalar opcional Value e HasValue. Os provedores devem implementar IHierarchicalConfigurationProvider antes que suas chaves apareçam durante a enumeração, mas você pode obter um caminho conhecido de qualquer provedor.
Arquivo de configuração JSON
O arquivo JSON segue uma estrutura hierárquica. Para acessar propriedades filhas, use o separador :. Por exemplo, considere uma configuração para uma estrutura de teste em potencial, como:
{
"CustomTestingFramework": {
"DisableParallelism": true
}
}
O snippet de código seria semelhante a este:
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 acessar o 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 é compatível com chaves hierárquicas de variáveis de ambiente em todas as plataformas.
__, o sublinhado duplo é:
- Compatível com todas as plataformas. Por exemplo, o
:separador não tem suporte do Bash, mas__é. - Substituição automática por um
:
Por exemplo, a variável de ambiente pode ser definida da seguinte maneira (este exemplo é aplicável ao Windows):
setx CustomTestingFramework__DisableParallelism=True
Você pode optar por não usar a fonte de configuração de 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 ICommandLineOptions serviço é 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);
}
ICommandLineOptions pode ser obtido por meio de determinadas APIs, como ICommandLineOptionsProvider, ou você pode recuperar uma instância dela do IServiceProvider por meio do método de extensão serviceProvider.GetCommandLineOptions().
ICommandLineOptions.IsOptionSet(string optionName): esse método permite que você verifique se uma opção específica foi especificada. Ao especificar o optionNameprefixo , omita o -- prefixo. Por exemplo, se o usuário inserir --myOption, basta passar myOption.
ICommandLineOptions.TryGetOptionArgumentList(string optionName, out string[]? arguments): esse método permite que você verifique se uma opção específica foi definida e, nesse caso, recupere o valor ou os valores correspondentes (se o arity for mais de 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 fornece às extensões a mesma modelagem de nome de arquivo multiplataforma que as extensões de relatório MTP usam. Recupere-o com serviceProvider.GetArtifactNamingService(), em seguida, chame ResolveFileName com um modelo.
O serviço expande {pname}, {pid}, {asm}, {tfm}, {arch} e {time}. Ele preserva os segmentos de diretório e normaliza o nome final do arquivo para o sistema operacional atual. Marcadores desconhecidos permanecem inalterados. Para descrições de marcadores, consulte Nomes de arquivos de relatório.
O serviço ILoggerFactory
A plataforma de teste vem com um sistema de log integrado que gera um arquivo de log. Você pode exibir as opções de registro atualizado 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 registrar informações, você precisa obter o ILoggerFactory do IServiceProvider.
A ILoggerFactory API é 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 registradores permite que você crie um objeto ILogger usando a API de 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 diversos níveis. Esses níveis de log incluem:
public enum LogLevel
{
Trace,
Debug,
Information,
Warning,
Error,
Critical,
None,
}
Aqui está um exemplo de como você pode usar a API de log:
...
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}'");
}
// ...
Tenha em mente que, para evitar a alocação desnecessária, verifique se o nível está habilitado usando a ILogger.IsEnabled(LogLevel) API.
O serviço IDiagnosticLoggingInformation
A partir do preview do MTP 2.5, chame serviceProvider.GetDiagnosticLoggingInformation() para obter informações experimentais sobre o registrador interno de arquivos de diagnóstico. O método retorna null quando o log de diagnóstico não está habilitado.
O IDiagnosticLoggingInformation serviço expõe:
-
LogFile, o arquivo que atualmente recebe entradas de diagnóstico. -
LogLevel, o nível mínimo gravado no arquivo. -
SynchronousWrite, que indica se o logger de arquivo grava registros de forma síncrona.
O serviço está ativo. Durante a construção do aplicativo de teste, o MTP pode realocar o log para o diretório de resultados efetivos. Mantenha o serviço e leia LogFile quando precisar do caminho em vez de armazenar em cache o primeiro FileInfo. Se a recuperação de log deixar um arquivo parcial no local original, LogFile identificará o arquivo de substituição que recebe novas entradas.
Importante
Essa API usa o ID de diagnóstico TPEXP e pode mudar ou ser removida em uma versão futura.
O serviço IMessageBus
O serviço de barramento de mensagens é o mecanismo central que facilita a troca de informações entre o framework de teste e suas extensões.
O barramento de mensagens da plataforma de teste emprega o padrão de publicação-assinatura.
A estrutura geral do barramento compartilhado é a seguinte:
Conforme ilustrado no diagrama, que inclui extensões e uma estrutura de teste, há duas ações potenciais: enviar informações para o barramento ou consumir informações do barramento.
O IMessageBus atendeu à ação de envio 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ções 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; é necessário declarar o tipo de dados a ser produzido antecipadamente. Se você enviar dados inesperados, uma exceção será acionada.IData: essa interface serve como um espaço reservado em que você só precisa fornecer detalhes descritivos, como o nome e uma descrição. A interface não revela muito sobre a natureza dos dados, o 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 registrada ou pelo próprio framework de teste.
Essa abordagem facilita a evolução do processo de troca de informações, evitando alterações que causam incompatibilidade quando uma extensão não está familiarizada com novos dados. Ele 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 é chamada de consumidor, que está inscrito em um tipo específico de dados e, portanto, pode consumi-los.
Importante
Sempre use aguarde para chamar para PublishAsync. Se você não fizer isso, talvez IData não seja processado corretamente pela plataforma de teste e extensões, o que pode levar a bugs sutis. É só depois que você retorna do await que pode ter certeza de que o IData foi enfileirado para processamento no barramento de mensagens. Independentemente do ponto de extensão em que você está trabalhando, certifique-se de ter aguardado todas as chamadas PublishAsync antes de sair da extensão. Por exemplo, se você estiver implementando o testing framework, não deverá chamar Complete nas solicitações até ter aguardado todas as chamadas PublishAsync relacionadas a essa solicitação específica.
O serviço ITestCoverageCapabilities
A partir do MTP 2.4, recupere ITestCoverageCapabilities de IServiceProvider para descobrir o suporte à cobertura-mensagem. O serviço expõe:
-
SupportsTestCoverageMessages, que indica suporte para o contrato de mensagem de cobertura da plataforma. -
EnabledProducerUids, um instantâneo de UIDs de produtor habilitados que declaram pelo menos um deTestCoverageMessage,TestCoverageThresholdMessageouTestCoverageReportMessage.
Leia a lista de produtores 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 registro ou construtor. Um produtor habilitado declara suporte; a lista não garante que o produtor já tenha publicado medidas. 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>() a partir de Microsoft.Testing.Platform.Services.
Para obter um exemplo de produtor e consumidor executável, consulte Publicar resultados de cobertura.
O serviço ITestCoverageResult
A partir do MTP 2.4, ITestCoverageResult fornece os dados de cobertura correlacionados da plataforma. Recupere o serviço IServiceProvider e use os seguintes membros:
| Membro | Purpose |
|---|---|
GetOverall(sessionUid) |
Retorna o resumo geral relatado da sessão ou null se nenhum existe. |
Scopes |
Retorna CoverageScopeSummary entradas com sua sessão, escopo e métricas. |
Thresholds |
Retorna as avaliações de limiar informadas, incluindo avaliações aprovadas e reprovadas. |
Reports |
Retorna referências de relatório de cobertura e seus formatos e IDs do produtor. |
HasThresholdFailure |
Indica se algum limiar relatado falhou. |
A chave de correlação de uma medida inclui a sessão, o produtor, o escopo, a métrica e o nome da métrica personalizada quando aplicável. Uma medida posterior com a mesma chave substitui o valor anterior; MTP não soma mensagens duplicadas. Produtores diferentes permanecem separados mesmo quando relatam a mesma métrica e escopo.
CoverageScopeSummary.Metrics preserva o valor de cada métricaProducerId. O indexador de conveniência, como summary[CoverageMetric.Line], retorna o primeiro resultado do produtor correspondente. Para selecionar um coletor específico, inspecione Metrics e faça a correspondência com ProducerId. Use GetCustom(name) para métricas personalizadas em vez do indexador.
Um resumo ausente significa que nenhuma medida correspondente foi relatada. Um resultado com HasCoverableData definido como false significa que o coletor relatou zero unidades cobríveis. Não substitua nenhum dos casos por um resultado bem-sucedido de 100%.
Como o barramento de mensagens processa dados de forma assíncrona, não consulte o serviço imediatamente depois de PublishAsync e suponha que a nova mensagem esteja presente. Para obter um resultado de fim de execução, leia após a conclusão da sessão, como o exemplo de cobertura faz em ITestHostApplicationLifetime.AfterRunAsync.
O serviço IClientInfo
Para identificar o cliente que controla um aplicativo de teste, chame serviceProvider.GetClientInfo() enquanto uma solicitação de teste ou sessão estiver ativa. No modo de servidor, o handshake de inicialização estabelece essas informações. O serviço experimental IClientInfo expõe Id, Versione Capabilities. A partir do MTP 2.4, Capabilities fornece um valor IClientCapabilities com a persistência de estado declarada pelo cliente.
Um cliente com estado reté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 o tempo de vida da conexão ou se o servidor aceita várias solicitações.
Use clientInfo.Capabilities.IsStateful para um resultado booliano conservador: uma funcionalidade não declarada retorna false. Para distinguir um explícito false de uma funcionalidade não declarada, use ClientCapabilitiesExtensions.GetIsStateful() no MTP 2.4.1 ou posterior:
| Result | Meaning |
|---|---|
true |
O cliente declara explicitamente o estado de nó de teste retido. |
false |
O cliente declara explicitamente o comportamento sem estado. |
null |
O serviço fornecido pela plataforma não possui declaração do cliente. |
Para uma implementação personalizada IClientCapabilities , GetIsStateful() retorna seu IsStateful valor. Para declarar a capacidade de um editor ou ferramenta, consulte Declarar estado do cliente.
Importante
IClientInfo, IClientCapabilities, GetClientInfo e ClientCapabilitiesExtensions são experimentais e usam a ID de diagnóstico TPEXP. A presença delas em um 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 dar suporte a dispositivos de saída personalizados, atualmente, esse ponto de extensão não está disponível.
Para transmitir dados ao dispositivo de saída, você deve obter o IOutputDevice de 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 IOutputDeviceData objeto:
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 com o 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, é totalmente viável implementar um aplicativo Web em tempo real que exibe o progresso dos testes.
O serviço IPlatformInformation
O serviço experimental IPlatformInformation fornece a plataforma Name, as opções Version e CommitHash, e a opção BuildDate.