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 inscrição expostas por pontos de extensão fornecem 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.
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:
- Variáveis de ambiente
- Um arquivo JSON chamado
[assemblyName].testingplatformconfig.jsonlocalizado próximo ao assembly do ponto de entrada.
A ordem de precedência é mantida, o que significa que, se uma configuração for encontrada nas variáveis de ambiente, o arquivo JSON não será processado.
A interface é um par de cadeias de caracteres chave-valor simples:
public interface IConfiguration
{
string? this[string key] { get; }
}
Arquivo de configuração JSON
O arquivo JSON segue uma estrutura hierárquica. Para acessar propriedades filhas, você precisa usar 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 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 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 mudanças incompatíveis 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 é conhecida como um consumidor, que está inscrito a 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 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);
}
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
}
});
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
Fornece informações sobre a plataforma, como: nome, versão, hash de confirmação e data de build.