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.
Este artigo aborda os pontos de extensibilidade do Microsoft.Testing.Platform para além do próprio framework de teste. Para criação de framework de teste, veja Construir um framework de teste.
Para o resumo completo do ponto de extensão e conceitos em processo/fora de processo, veja Criar extensões personalizadas.
Pontos de extensibilidade
A plataforma de teste fornece pontos de extensibilidade adicionais que permitem personalizar o comportamento da plataforma e da estrutura de teste. Esses pontos de extensibilidade são opcionais e podem ser usados para melhorar a experiência de teste.
As extensões ICommandLineOptionsProvider
Observação
Ao estender essa API, a extensão personalizada existirá dentro e fora do processo de host de teste.
Conforme discutido na seção de arquitetura , a etapa inicial envolve a criação do ITestApplicationBuilder para registrar a estrutura de teste e as extensões com ela.
var builder = await TestApplication.CreateBuilderAsync(args);
O método CreateBuilderAsync aceita uma matriz de cadeias de caracteres (string[]) chamada args. Esses argumentos podem ser usados para passar opções de linha de comando para todos os componentes da plataforma de teste (incluindo componentes internos, estruturas de teste e extensões), permitindo a personalização de seu comportamento.
Normalmente, os argumentos passados são aqueles recebidos no método Main(string[] args) padrão. No entanto, se o ambiente de hospedagem for diferente, qualquer lista de argumentos pode ser fornecida.
Os argumentos devem ser prefixados com um traço duplo --. Por exemplo, --filter.
Se um componente, como uma estrutura de teste ou um ponto de extensão, desejar oferecer opções de linha de comando personalizadas, ele poderá fazê-lo implementando a interface ICommandLineOptionsProvider. Esta implementação pode então ser registada junto da ITestApplicationBuilder através da fábrica de registo do imóvel CommandLine, conforme demonstrado:
builder.CommandLine.AddProvider(
static () => new CustomCommandLineOptions());
No exemplo fornecido, CustomCommandLineOptions é uma implementação da interface ICommandLineOptionsProvider, Esta interface compreende os seguintes membros e tipos de dados:
public interface ICommandLineOptionsProvider : IExtension
{
IReadOnlyCollection<CommandLineOption> GetCommandLineOptions();
Task<ValidationResult> ValidateOptionArgumentsAsync(
CommandLineOption commandOption,
string[] arguments);
Task<ValidationResult> ValidateCommandLineOptionsAsync(
ICommandLineOptions commandLineOptions);
}
public sealed class CommandLineOption
{
public string Name { get; }
public string Description { get; }
public ArgumentArity Arity { get; }
public bool IsHidden { get; }
// ...
}
public interface ICommandLineOptions
{
bool IsOptionSet(string optionName);
bool TryGetOptionArgumentList(
string optionName,
out string[]? arguments);
}
Como observado, o ICommandLineOptionsProvider estende a interface IExtension. Portanto, como qualquer outra extensão, você pode optar por habilitá-la ou desativá-la usando a API IExtension.IsEnabledAsync.
A ordem de execução do ICommandLineOptionsProvider é:
Vamos examinar as apis e sua média:
ICommandLineOptionsProvider.GetCommandLineOptions(): Este método é utilizado para recuperar todas as opções oferecidas pelo componente. Cada CommandLineOption requer que as seguintes propriedades sejam especificadas:
string name: Este é o nome da opção, apresentado sem traço. Por exemplo, o filtro seria utilizado como --filter pelos utilizadores.
string description: Esta é uma descrição da opção. Será exibido quando os usuários passarem o --help como argumento para o construtor da aplicação.
ArgumentArity arity: A aridade de uma opção é o número de valores que podem ser passados se essa opção ou comando for especificado. As aridades disponíveis atualmente são:
-
Zero: Representa uma aridade de argumento nula. -
ZeroOrOne: Representa uma aridade de argumento de zero ou um. -
ZeroOrMore: Indica uma aridade de argumentos que pode ser nula ou superior. -
OneOrMore: Representa um ou mais argumentos. -
ExactlyOne: Representa uma aridade de argumento de exatamente um.
Para obter exemplos, consulte a tabela de aridade do System.CommandLine .
bool isHidden: Esta propriedade significa que a opção está disponível para uso, mas não será exibida na descrição quando --help for invocada.
ICommandLineOptionsProvider.ValidateOptionArgumentsAsync: Este método é empregado para validar o argumento fornecido pelo usuário.
Por exemplo, se você tiver um parâmetro chamado --dop que representa o grau de paralelismo para nossa estrutura de teste personalizada, um usuário poderá inserir --dop 0. Nesse cenário, o valor 0 seria inválido porque se espera que tenha um grau de paralelismo de 1 ou mais. Usando ValidateOptionArgumentsAsync, você pode executar a validação inicial e retornar uma mensagem de erro, se necessário.
Uma possível implementação para a amostra acima poderia ser:
public Task<ValidationResult> ValidateOptionArgumentsAsync(
CommandLineOption commandOption,
string[] arguments)
{
if (commandOption.Name == "dop")
{
if (!int.TryParse(arguments[0], out int dopValue) || dopValue <= 0)
{
return ValidationResult.InvalidTask("--dop must be a positive integer");
}
}
return ValidationResult.ValidTask;
}
ICommandLineOptionsProvider.ValidateCommandLineOptionsAsync: Este método é chamado como último e permite fazer verificação de coerência global.
Por exemplo, digamos que nossa estrutura de teste tenha a capacidade de gerar um relatório de resultado de teste e salvá-lo em um arquivo. Esse recurso é acessado usando a opção --generatereport e o nome do arquivo é especificado com --reportfilename myfile.rep. Nesse cenário, se um usuário fornece apenas a opção --generatereport sem especificar um nome de arquivo, a validação deve falhar porque o relatório não pode ser gerado sem um nome de arquivo.
Uma possível implementação para a amostra acima poderia ser:
public Task<ValidationResult> ValidateCommandLineOptionsAsync(ICommandLineOptions commandLineOptions)
{
bool generateReportEnabled = commandLineOptions.IsOptionSet(GenerateReportOption);
bool reportFileName = commandLineOptions.TryGetOptionArgumentList(ReportFilenameOption, out string[]? _);
return (generateReportEnabled || reportFileName) && !(generateReportEnabled && reportFileName)
? ValidationResult.InvalidTask("Both `--generatereport` and `--reportfilename` need to be provided simultaneously.")
: ValidationResult.ValidTask;
}
Observe que o método ValidateCommandLineOptionsAsync fornece o serviço ICommandLineOptions, que é usado para buscar as informações do argumento analisadas pela própria plataforma.
As extensões ITestSessionLifetimeHandler
O ITestSessionLifeTimeHandler é uma extensão de em processo que permite a execução de código antes e depois a sessão de teste.
Para registrar um ITestSessionLifeTimeHandlerpersonalizado, utilize a seguinte API:
var builder = await TestApplication.CreateBuilderAsync(args);
// ...
builder.TestHost.AddTestSessionLifetimeHandle(
static serviceProvider => new CustomTestSessionLifeTimeHandler());
A fábrica utiliza o IServiceProvider para obter acesso ao conjunto de serviços oferecidos pela plataforma de testes.
Importante
A sequência de registro é significativa, pois as APIs são chamadas na ordem em que foram registradas.
A interface ITestSessionLifeTimeHandler inclui os seguintes métodos:
public interface ITestSessionLifetimeHandler : ITestHostExtension
{
Task OnTestSessionStartingAsync(
SessionUid sessionUid,
CancellationToken cancellationToken);
Task OnTestSessionFinishingAsync(
SessionUid sessionUid,
CancellationToken cancellationToken);
}
public readonly struct SessionUid(string value)
{
public string Value { get; } = value;
}
public interface ITestHostExtension : IExtension
{
}
O ITestSessionLifetimeHandler é um tipo de ITestHostExtension, que serve como base para todas as extensões de host de teste . Como todos os outros pontos de extensão, ele também herda de IExtension. Portanto, como qualquer outra extensão, você pode optar por habilitá-la ou desativá-la usando a API IExtension.IsEnabledAsync.
Considere os seguintes detalhes para esta API:
OnTestSessionStartingAsync: Este método é invocado antes do início da sessão de teste e recebe o objeto SessionUid, que fornece um identificador opaco para a sessão de teste atual.
OnTestSessionFinishingAsync: Este método é invocado após a conclusão da sessão de teste, garantindo que a estrutura de teste terminou de executar todos os testes e relatou todos os dados relevantes para a plataforma. Normalmente, neste método, a extensão emprega o IMessageBus para transmitir recursos ou dados personalizados para o barramento de plataforma compartilhada. Este método também pode sinalizar para qualquer extensão fora do processo personalizada que a sessão de teste foi concluída.
Por fim, ambas as APIs aceitam um CancellationToken que se espera que a extensão honre.
Se a tua extensão exigir uma inicialização intensiva e precisares de usar o padrão async/await, podes consultar o Async extension initialization and cleanup. Se você precisar compartilhar de estado entre os pontos de extensão, consulte a seção CompositeExtensionFactory<T>.
As extensões ITestApplicationLifecycleCallbacks
O ITestApplicationLifecycleCallbacks é uma extensão em processo que permite a execução de código antes de qualquer coisa, é como ter acesso à primeira linha do hipotético principal do host de teste .
Para registrar um ITestApplicationLifecycleCallbackspersonalizado, utilize a seguinte api:
var builder = await TestApplication.CreateBuilderAsync(args);
// ...
builder.TestHost.AddTestApplicationLifecycleCallbacks(
static serviceProvider
=> new CustomTestApplicationLifecycleCallbacks());
A fábrica utiliza o IServiceProvider para obter acesso ao conjunto de serviços oferecidos pela plataforma de testes.
Importante
A sequência de registro é significativa, pois as APIs são chamadas na ordem em que foram registradas.
A interface ITestApplicationLifecycleCallbacks inclui os seguintes métodos:
public interface ITestApplicationLifecycleCallbacks : ITestHostExtension
{
Task BeforeRunAsync(CancellationToken cancellationToken);
Task AfterRunAsync(
int exitCode,
CancellationToken cancellation);
}
public interface ITestHostExtension : IExtension
{
}
O ITestApplicationLifecycleCallbacks é um tipo de ITestHostExtension, que serve como base para todas as extensões de host de teste . Como todos os outros pontos de extensão, ele também herda de IExtension. Portanto, como qualquer outra extensão, você pode optar por habilitá-la ou desativá-la usando a API IExtension.IsEnabledAsync.
BeforeRunAsync: Este método serve como o ponto de contacto inicial para o host de teste e é a primeira oportunidade para uma extensão em execução ativar uma funcionalidade. Normalmente, é usado para estabelecer uma conexão com quaisquer extensões correspondentes fora de processo, caso uma funcionalidade seja projetada para operar em ambos os ambientes.
Por exemplo, o recurso de hang dump interno é composto por em processo e extensões de fora de processo, e esse método é usado para trocar informações com o componente fora de processo da extensão.
AfterRunAsync: Este método é a invocação final antes de sair do int ITestApplication.RunAsync() e fornece o exit code. Deve ser utilizado exclusivamente para tarefas de limpeza e para notificar qualquer extensão correspondente fora de processo que o host de teste está prestes a terminar.
Por fim, ambas as APIs aceitam um CancellationToken que se espera que a extensão honre.
As extensões IDataConsumer
O IDataConsumer é uma extensão de em processo capaz de assinar e receber informações IData que são enviadas para o IMessageBus pela estrutura de teste e suas extensões.
Este ponto de extensão é crucial, pois permite que os desenvolvedores reúnam e processem todas as informações geradas durante uma sessão de teste.
Para registrar um IDataConsumerpersonalizado, utilize a seguinte api:
var builder = await TestApplication.CreateBuilderAsync(args);
// ...
builder.TestHost.AddDataConsumer(
static serviceProvider => new CustomDataConsumer());
A fábrica utiliza o IServiceProvider para obter acesso ao conjunto de serviços oferecidos pela plataforma de testes.
Importante
A sequência de registro é significativa, pois as APIs são chamadas na ordem em que foram registradas.
A interface IDataConsumer inclui os seguintes métodos:
public interface IDataConsumer : ITestHostExtension
{
Type[] DataTypesConsumed { get; }
Task ConsumeAsync(
IDataProducer dataProducer,
IData value,
CancellationToken cancellationToken);
}
public interface IData
{
string DisplayName { get; }
string? Description { get; }
}
O IDataConsumer é um tipo de ITestHostExtension, que serve como base para todas as extensões de host de teste . Como todos os outros pontos de extensão, ele também herda de IExtension. Portanto, como qualquer outra extensão, você pode optar por habilitá-la ou desativá-la usando a API IExtension.IsEnabledAsync.
DataTypesConsumed: Esta propriedade retorna uma lista de Type que esta extensão planeia consumir. Corresponde a IDataProducer.DataTypesProduced. Notavelmente, um IDataConsumer pode inscrever-se em vários tipos provenientes de diferentes instâncias de IDataProducer sem quaisquer problemas.
ConsumeAsync: Este método é acionado sempre que dados de um tipo ao qual o consumidor atual está subscrito são enviados para o IMessageBus. Ele recebe o IDataProducer para fornecer detalhes sobre o produtor da carga útil de dados, bem como a própria carga útil IData. Como podes ver, IData é uma interface de espaço reservado genérica que contém dados gerais informativos. A capacidade de empurrar diferentes tipos de IData implica que o consumidor precisa mudar no próprio tipo para lançá-lo para o tipo correto e acessar as informações específicas.
Um exemplo de implementação de um consumidor que deseja elaborar o TestNodeUpdateMessage produzido por um framework de teste poderia ser:
internal class CustomDataConsumer : IDataConsumer, IOutputDeviceDataProducer
{
public Type[] DataTypesConsumed => new[] { typeof(TestNodeUpdateMessage) };
...
public Task ConsumeAsync(
IDataProducer dataProducer,
IData value,
CancellationToken cancellationToken)
{
var testNodeUpdateMessage = (TestNodeUpdateMessage)value;
switch (testNodeUpdateMessage.TestNode.Properties.Single<TestNodeStateProperty>())
{
case InProgressTestNodeStateProperty _:
{
...
break;
}
case PassedTestNodeStateProperty _:
{
...
break;
}
case FailedTestNodeStateProperty failedTestNodeStateProperty:
{
...
break;
}
case SkippedTestNodeStateProperty _:
{
...
break;
}
...
}
return Task.CompletedTask;
}
...
}
Finalmente, a API aceita um CancellationToken que se espera que a extensão respeite.
Importante
É crucial processar a carga diretamente dentro do método ConsumeAsync. O IMessageBus pode gerenciar o processamento síncrono e assíncrono, coordenando a execução com a estrutura de teste . Embora o processo de consumo seja totalmente assíncrono e não bloqueie o IMessageBus.Push no momento da escrita, este é um detalhe de implementação que pode mudar no futuro devido a requisitos futuros. No entanto, a plataforma garante que esse método seja sempre chamado uma vez, eliminando a necessidade de sincronização complexa, além de gerenciar a escalabilidade dos consumidores.
Advertência
Ao usar IDataConsumer em conjunto com ITestHostProcessLifetimeHandler dentro de um ponto de extensão composto , é crucial desconsiderar quaisquer dados recebidos após a execução de ITestSessionLifetimeHandler.OnTestSessionFinishingAsync. O OnTestSessionFinishingAsync é a última oportunidade de processar dados acumulados e transmitir novas informações ao IMessageBus, portanto, quaisquer dados consumidos além deste ponto não serão utilizáveis pela extensão.
Se a tua extensão exigir uma inicialização intensiva e precisares de usar o padrão async/await, podes consultar o Async extension initialization and cleanup. Se você precisar compartilhar de estado entre os pontos de extensão, consulte a seção CompositeExtensionFactory<T>.
As extensões ITestHostEnvironmentVariableProvider
A ITestHostEnvironmentVariableProvider é uma extensão de fora de processo que permite estabelecer variáveis de ambiente personalizadas para o host de teste. A utilização desse ponto de extensão garante que a plataforma de teste inicie um novo host com as variáveis de ambiente apropriadas, conforme detalhado na seção arquitetura.
Para registrar um ITestHostEnvironmentVariableProviderpersonalizado, utilize a seguinte API:
var builder = await TestApplication.CreateBuilderAsync(args);
// ...
builder.TestHostControllers.AddEnvironmentVariableProvider(
static serviceProvider => new CustomEnvironmentVariableForTestHost());
A fábrica utiliza o IServiceProvider para obter acesso ao conjunto de serviços oferecidos pela plataforma de testes.
Importante
A sequência de registro é significativa, pois as APIs são chamadas na ordem em que foram registradas.
A interface ITestHostEnvironmentVariableProvider inclui os seguintes métodos e tipos:
public interface ITestHostEnvironmentVariableProvider : ITestHostControllersExtension, IExtension
{
Task UpdateAsync(IEnvironmentVariables environmentVariables);
Task<ValidationResult> ValidateTestHostEnvironmentVariablesAsync(
IReadOnlyEnvironmentVariables environmentVariables);
}
public interface IEnvironmentVariables : IReadOnlyEnvironmentVariables
{
void SetVariable(EnvironmentVariable environmentVariable);
void RemoveVariable(string variable);
}
public interface IReadOnlyEnvironmentVariables
{
bool TryGetVariable(
string variable,
[NotNullWhen(true)] out OwnedEnvironmentVariable? environmentVariable);
}
public sealed class OwnedEnvironmentVariable : EnvironmentVariable
{
public IExtension Owner { get; }
public OwnedEnvironmentVariable(
IExtension owner,
string variable,
string? value,
bool isSecret,
bool isLocked);
}
public class EnvironmentVariable
{
public string Variable { get; }
public string? Value { get; }
public bool IsSecret { get; }
public bool IsLocked { get; }
}
O ITestHostEnvironmentVariableProvider é um tipo de ITestHostControllersExtension, que serve como base para todas as extensões de do controlador de host de teste. Como todos os outros pontos de extensão, ele também herda de IExtension. Portanto, como qualquer outra extensão, você pode optar por habilitá-la ou desativá-la usando a API IExtension.IsEnabledAsync.
Considere os detalhes desta API:
UpdateAsync: Esta API de atualização fornece uma instância do objeto IEnvironmentVariables, a partir do qual você pode chamar os métodos SetVariable ou RemoveVariable. Ao usar SetVariable, você deve passar um objeto do tipo EnvironmentVariable, que requer as seguintes especificações:
-
Variable: O nome da variável de ambiente. -
Value: O valor da variável de ambiente. -
IsSecret: Isso indica se a variável de ambiente contém informações confidenciais que não devem ser registradas ou acessíveis através doTryGetVariable. -
IsLocked: Isso determina se outras extensõesITestHostEnvironmentVariableProviderpodem modificar esse valor.
ValidateTestHostEnvironmentVariablesAsync: Este método é invocado depois que todos os métodos UpdateAsync das instâncias de ITestHostEnvironmentVariableProvider registradas foram chamados. Ele permite que você verifique a configuração correta das variáveis de ambiente. Ele usa um objeto que implementa IReadOnlyEnvironmentVariables, que fornece o método TryGetVariable para buscar informações de variáveis de ambiente específicas com o tipo de objeto OwnedEnvironmentVariable. Após a validação, você retorna um ValidationResult contendo quaisquer motivos de falha.
Observação
A plataforma de teste, por padrão, implementa e registra o SystemEnvironmentVariableProvider. Esse provedor carrega todas as variáveis de ambiente atuais. Como o primeiro provedor registrado, ele é executado primeiro, concedendo acesso às variáveis de ambiente padrão para todas as outras extensões de usuário ITestHostEnvironmentVariableProvider.
Se a tua extensão exigir uma inicialização intensiva e precisares de usar o padrão async/await, podes consultar o Async extension initialization and cleanup. Se você precisar compartilhar de estado entre os pontos de extensão, consulte a seção CompositeExtensionFactory<T>.
As extensões ITestHostProcessLifetimeHandler
O ITestHostProcessLifetimeHandler é uma extensão fora do processo que permite que você observe o processo do host de teste a partir de um ponto de vista externo. Isso garante que sua extensão não seja afetada por possíveis falhas ou travamentos que possam ser induzidos pelo código em teste. A utilização deste ponto de extensão fará com que a plataforma de teste inicie um novo host, conforme detalhado na seção arquitetura.
Para registrar um ITestHostProcessLifetimeHandlerpersonalizado, utilize a seguinte API:
var builder = await TestApplication.CreateBuilderAsync(args);
// ...
builder.TestHostControllers.AddProcessLifetimeHandler(
static serviceProvider => new CustomMonitorTestHost());
A fábrica utiliza o IServiceProvider para obter acesso ao conjunto de serviços oferecidos pela plataforma de testes.
Importante
A sequência de registro é significativa, pois as APIs são chamadas na ordem em que foram registradas.
A interface ITestHostProcessLifetimeHandler inclui os seguintes métodos:
public interface ITestHostProcessLifetimeHandler : ITestHostControllersExtension
{
Task BeforeTestHostProcessStartAsync(CancellationToken cancellationToken);
Task OnTestHostProcessStartedAsync(
ITestHostProcessInformation testHostProcessInformation,
CancellationToken cancellation);
Task OnTestHostProcessExitedAsync(
ITestHostProcessInformation testHostProcessInformation,
CancellationToken cancellation);
}
public interface ITestHostProcessInformation
{
int PID { get; }
int ExitCode { get; }
bool HasExitedGracefully { get; }
}
O ITestHostProcessLifetimeHandler é um tipo de ITestHostControllersExtension, que serve como base para todas as extensões de do controlador de host de teste. Como todos os outros pontos de extensão, ele também herda de IExtension. Portanto, como qualquer outra extensão, você pode optar por habilitá-la ou desativá-la usando a API IExtension.IsEnabledAsync.
Considere os seguintes detalhes para esta API:
BeforeTestHostProcessStartAsync: Este método é invocado antes da plataforma de teste iniciar os hosts de teste.
OnTestHostProcessStartedAsync: Este método é invocado imediatamente após o início do host de teste. Esse método oferece um objeto que implementa a interface ITestHostProcessInformation, que fornece detalhes importantes sobre o resultado do processo do host de teste.
Importante
A invocação desse método não interrompe a execução do host de teste. Se você precisar pausá-lo, registre uma extensão deem processo, como ITestApplicationLifecycleCallbacks, e sincronize-a com a extensão fora de processo.
OnTestHostProcessExitedAsync: Este método é invocado quando a execução do conjunto de testes é concluída. Este método fornece um objeto que adere à interface ITestHostProcessInformation, que transmite detalhes cruciais sobre o resultado do processo de host de teste.
A interface ITestHostProcessInformation fornece os seguintes detalhes:
-
PID: O ID do processo do anfitrião de teste. -
ExitCode: O código de saída do processo. Esse valor só está disponível dentro do métodoOnTestHostProcessExitedAsync. Tentar acessá-lo dentro do métodoOnTestHostProcessStartedAsyncresultará em uma exceção. -
HasExitedGracefully: Um valor booleano que indica se o host de teste falhou. Se verdadeiro, significa que o host de teste não saiu normalmente.
Prorrogações de ordem de execução
A plataforma de teste consiste em uma estrutura de teste e qualquer número de extensões que podem operar em processo ou fora do processo. Este documento descreve a sequência de chamadas a todos os potenciais pontos de extensibilidade para fornecer clareza sobre quando se prevê que um recurso seja invocado:
- ITestHostEnvironmentVariableProvider.UpdateAsync : Fora do processo
- ITestHostEnvironmentVariableProvider.ValidateTestHostEnvironmentVariablesAsync : Fora do contexto do processo
- ITestHostProcessLifetimeHandler.BeforeTestHostProcessStartAsync : Fora do processo
- Início do processo de teste de host
- ITestHostProcessLifetimeHandler.OnTestHostProcessStartedAsync : Fora do processo, esse evento pode entrelaçar as ações de extensões de em processo, dependendo das condições de corrida.
- ITestApplicationLifecycleCallbacks.BeforeRunAsync: Em processo
- ITestSessionLifetimeHandler.OnTestSessionStartingAsync: Em processo
- ITestFramework.CreateTestSessionAsync: Em processo
- ITestFramework.ExecuteRequestAsync: Em processo, esse método pode ser chamado uma ou mais vezes. Neste ponto, a estrutura de teste transmitirá informações para o IMessageBus que podem ser utilizadas pelo IDataConsumer.
- ITestFramework.CloseTestSessionAsync: Em execução
- ITestSessionLifetimeHandler.OnTestSessionFinishingAsync: Em execução
- ITestApplicationLifecycleCallbacks.AfterRunAsync: Em execução
- A limpeza em processo envolve chamar o descartar e IAsyncCleanableExtension em todos os pontos de extensão.
- ITestHostProcessLifetimeHandler.OnTestHostProcessExitedAsync : Fora do processo
- A limpeza fora do processo envolve chamar o método dispose e IAsyncCleanableExtension em todos os pontos de extensão.
Auxiliares de extensões
A plataforma de teste fornece um conjunto de classes auxiliares e interfaces para simplificar a implementação de extensões. Esses auxiliares são projetados para agilizar o processo de desenvolvimento e garantir que a extensão siga os padrões da plataforma.
Inicialização assíncrona e limpeza de extensões
A criação do framework de testes e das extensões através das fábricas segue o mecanismo padrão de criação de objetos .NET, que utiliza construtores síncronos. Se uma extensão requer inicialização intensiva (como acessar o sistema de arquivos ou a rede), ela não pode empregar o padrão async/await no construtor porque os construtores retornam void, não Task.
Portanto, a plataforma de teste fornece um método para inicializar uma extensão usando o padrão async/await por meio de uma interface simples. Por razões de simetria, também oferece uma interface assíncrona para limpeza que as extensões podem implementar sem esforço.
public interface IAsyncInitializableExtension
{
Task InitializeAsync();
}
public interface IAsyncCleanableExtension
{
Task CleanupAsync();
}
IAsyncInitializableExtension.InitializeAsync: Este método é garantido para ser invocado após a fábrica de criação.
IAsyncCleanableExtension.CleanupAsync: Este método tem a garantia de ser invocado pelo menos uma vez durante o término da sessão de teste, antes do DisposeAsync ou Disposepadrão.
Importante
Semelhante ao método padrão Dispose, CleanupAsync pode ser invocado várias vezes. Se o método CleanupAsync de um objeto for chamado mais de uma vez, o objeto deverá ignorar todas as chamadas após a primeira. O objeto não deve lançar uma exceção se seu método CleanupAsync for chamado várias vezes.
Observação
Por padrão, a plataforma de teste chamará DisposeAsync se estiver disponível ou Dispose se estiver implementada. É importante notar que a plataforma de teste não chamará os dois métodos dispose, mas dará prioridade ao assíncrono, se este for implementado.
O CompositeExtensionFactory<T>
Conforme descrito na seção de extensões , a plataforma de teste permite-lhe implementar interfaces para incorporar extensões personalizadas, tanto internamente como externamente ao processo.
Cada interface aborda uma funcionalidade específica e, de acordo com o design .NET, implementa-se essa interface num objeto específico. Você pode registrar a própria extensão usando a API de registro específica AddXXX do objeto TestHost ou TestHostController do ITestApplicationBuilder conforme detalhado nas seções correspondentes.
No entanto, se necessitar de partilhar estado entre duas extensões, o facto de poder implementar e registar objetos diferentes que implementam interfaces diferentes torna a partilha uma tarefa desafiadora. Sem qualquer assistência, você precisaria de uma maneira de passar uma extensão para a outra para compartilhar informações, o que complica o design.
Assim, a plataforma de teste fornece um método sofisticado para implementar vários pontos de extensão usando o mesmo tipo, tornando o compartilhamento de dados uma tarefa simples. Tudo o que você precisa fazer é utilizar o CompositeExtensionFactory<T>, que pode ser registrado usando a mesma API que você faria para uma única implementação de interface.
Por exemplo, considere um tipo que implementa ITestSessionLifetimeHandler e IDataConsumer. Esse é um cenário comum porque muitas vezes você deseja coletar informações da estrutura de teste e, em seguida, quando a sessão de teste for concluída, você enviará seu artefato usando o IMessageBus dentro do ITestSessionLifetimeHandler.OnTestSessionFinishingAsync.
O que você deve fazer é implementar normalmente as interfaces:
internal class CustomExtension : ITestSessionLifetimeHandler, IDataConsumer, ...
{
...
}
Depois de criares o CompositeExtensionFactory<CustomExtension> para o teu tipo, podes registá-lo com as APIs IDataConsumer e ITestSessionLifetimeHandler, que oferecem uma sobrecarga para o CompositeExtensionFactory<T>:
var builder = await TestApplication.CreateBuilderAsync(args);
// ...
var factory = new CompositeExtensionFactory<CustomExtension>(serviceProvider => new CustomExtension());
builder.TestHost.AddTestSessionLifetimeHandle(factory);
builder.TestHost.AddDataConsumer(factory);
O construtor da fábrica emprega o IServiceProvider para acessar os serviços fornecidos pela plataforma de teste.
A plataforma de teste será responsável por gerenciar o ciclo de vida da extensão composta.
É importante notar que, devido ao suporte da plataforma de teste para extensões em-processo e fora-de-processo , não se pode combinar nenhum ponto de extensão arbitrariamente. A criação e a utilização de extensões dependem do tipo de host, o que significa que você só pode agrupar extensões em processo (TestHost) e fora de processo (TestHostController) juntas.
São possíveis as seguintes combinações:
- Por
ITestApplicationBuilder.TestHost, você pode combinarIDataConsumereITestSessionLifetimeHandler. - Por
ITestApplicationBuilder.TestHostControllers, você pode combinarITestHostEnvironmentVariableProvidereITestHostProcessLifetimeHandler.