Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
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 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 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 registro 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 parâmetro.
O serviço IConfiguration
A interface IConfiguration pode ser recuperada usando o IServiceProvider e fornece acesso às definições de configuração para a estrutura de teste e quaisquer 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 perto do 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 as propriedades filho, você precisa 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 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 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 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 IMessageBus
O serviço de barramento de mensagens é o mecanismo central que facilita a troca de informações entre a estrutura de teste e 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 significativas 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 é referida como um consumidor, que está subscrito a um tipo específico de dados e, portanto, pode consumi-lo.
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 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);
}
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
}
});
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
Fornece informações sobre a plataforma, tais como: nome, versão, hash de confirmação e data de compilação.