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.
No contexto do MTP, uma funcionalidade refere-se ao potencial de executar uma ação específica ou fornecer informações específicas. É um meio para a estrutura de teste e extensões declararem sua capacidade de operar de determinada maneira ou fornecer informações específicas aos solicitantes.
Os solicitantes podem ser qualquer componente envolvido em uma sessão de teste, como a plataforma, uma extensão ou a própria estrutura de teste.
O objetivo principal do sistema de funcionalidade é facilitar a comunicação efetiva entre os componentes envolvidos em uma sessão de teste, permitindo que eles exchange informações e atendam às respectivas necessidades com precisão.
Exemplo guiado
Vamos considerar um exemplo hipotético para demonstrar a necessidade de um sistema de funcionalidades.
Observação
Este exemplo é puramente para fins ilustrativos e não é implementado atualmente no MTP ou em qualquer estrutura de teste.
Imagine uma situação em que você tenha uma extensão que exija que a estrutura de teste execute não mais do que um teste por vez. Além disso, após cada teste, a extensão precisa saber o uso da CPU para esse teste específico.
Para acomodar o cenário anterior, você precisará consultar a estrutura de teste se:
- Ele tem a capacidade de executar apenas um teste por vez.
- Ele pode fornecer informações sobre a quantidade de CPU consumida por cada teste.
Como a extensão pode determinar se a estrutura de teste tem a capacidade de operar nesse modo e fornecer informações de uso da CPU para uma sessão de teste? No MTP, essa funcionalidade é representada por uma implementação da interface Microsoft.Testing.Platform.Capabilities.ICapability:
// Base capabilities contracts
public interface ICapability
{
}
public interface ICapabilities<TCapability>
where TCapability : ICapability
{
IReadOnlyCollection<TCapability> Capabilities { get; }
}
// Specific testing framework capabilities
public interface ITestFrameworkCapabilities : ICapabilities<ITestFrameworkCapability>
{
}
public interface ITestFrameworkCapability : ICapability
{
}
Como você pode ver, a ICapability interface é uma interface de marcador porque pode representar qualquer funcionalidade e a implementação real dependerá do contexto. Você também observará o ITestFrameworkCapability, que herda de ICapability para classificar a capacidade. A natureza genérica do sistema de funcionalidades permite o agrupamento conveniente por contexto. O ITestFrameworkCapability agrupa todos os recursos implementados pelo framework de teste. A ICapabilities<TCapability> interface revela o conjunto de todos os recursos implementados por uma extensão. Da mesma forma, para a base um, há uma estrutura de teste específica para o contexto chamada ITestFrameworkCapabilities. O ITestFrameworkCapabilities é fornecido à plataforma durante o processo de registro do framework de teste.
Para criar um recurso que resolva o cenário mencionado acima, defina-o da seguinte maneira:
public interface IDisableParallelismCapability : ITestFrameworkCapability
{
bool CanDisableParallelism { get; }
bool CanProvidePerTestCpuConsumption { get; }
void Enable();
}
Se a estrutura de teste implementar essa interface, em runtime, o seguinte poderá ser consultado:
- Verifique se a estrutura de teste tem a capacidade de desativar o paralelismo
CanDisableParallelism = true. - Determine se a estrutura de teste pode fornecer dados
CanProvidePerTestCPUConsumption = truede uso da CPU. - Solicite que o adaptador de teste ative esse modo invocando o
Enable()método antes do início da sessão de teste.
O fragmento de código hipotético dentro da extensão pode ser algo como:
IServiceProvider serviceProvider = null; // TODO: Get IServiceProvider.
var capabilities = serviceProvider.GetRequiredService<ITestFrameworkCapabilities>();
// Utilize the `GetCapability` API to search for the specific capability to query.
var capability = capabilities.GetCapability<IDisableParallelismCapability>();
if (capability is null)
{
// Capability not supported...
}
else
{
capability.Enable();
if (capability.CanDisableParallelism)
{
// Do something...
}
if (capability.CanProvidePerTestCpuConsumption)
{
// Do something...
}
}
O exemplo anterior ilustra como a infraestrutura de funcionalidade permite um mecanismo poderoso para comunicar habilidades entre os componentes envolvidos em uma sessão de teste. Embora o exemplo demonstre uma funcionalidade especificamente projetada para a estrutura de teste, qualquer componente pode expor e implementar extensões que herdam de ICapability.
É evidente que nem todos os detalhes podem ser comunicados por meio de uma interface. Considerando o exemplo anterior, o que a extensão deve esperar se houver suporte para CanProvidePerTestCpuConsumption? Que tipo de informações personalizadas devem ser transmitidas por meio do IMessageBus pela estrutura de teste? A solução é a documentação da funcionalidade. É responsabilidade do proprietário da funcionalidade projetar, enviar e documentá-lo o mais claramente possível para ajudar os implementadores que desejam colaborar efetivamente com a extensão que requer a funcionalidade específica.
Por exemplo, a extensão de relatório TRX permite que a estrutura de teste implemente a capacidade necessária para gerar com precisão um relatório TRX. A extensão para registro está incluída no pacote NuGet https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport, mas a capacidade de implementação é encontrada no pacote apenas no contrato.
Em conclusão, vamos resumir os principais aspectos do sistema de funcionalidade:
- É essencial para facilitar a comunicação clara e estável entre componentes.
- Todos os recursos devem herdar de
ICapabilityou de uma interface que herda dele e são expostos por meio de uma coleção com a interfaceICapabilities. - Ajuda na evolução dos recursos sem causar alterações significativas. Se uma determinada funcionalidade não tiver suporte, medidas apropriadas poderão ser tomadas.
- A responsabilidade de projetar, enviar e documentar o uso de uma funcionalidade é do proprietário da funcionalidade. O MTP também pode ter uma funcionalidade da mesma forma que qualquer outra extensão.
Funcionalidades da estrutura
A plataforma expõe uma interface especializada chamada ITestFrameworkCapability que é a base de todos os recursos expostos para estruturas de teste. Esses recursos são fornecidos ao registrar a estrutura de teste na plataforma.
IBannerMessageOwnerCapability
Uma capacidade opcional do framework de teste permite que o framework de teste forneça a mensagem de banner à plataforma. Se a mensagem for null ou o recurso não estiver presente, a plataforma usará sua mensagem padrão do banner.
Essa implementação de funcionalidade permite que você abstraia as várias condições que a estrutura de teste pode precisar considerar ao decidir se a mensagem de faixa deve ou não ser exibida.
A plataforma expõe o IPlatformInformation serviço para fornecer algumas informações sobre a plataforma que podem ser úteis ao criar sua mensagem de banner personalizada.
ITrxReportCapability
Para fornecer metadados específicos do framework para a extensão de relatório TRX, implemente Microsoft.Testing.Extensions.TrxReport.Abstractions.ITrxReportCapability. Referencie o pacote Microsoft.Testing.Extensions.TrxReport.Abstractions do seu framework. O aplicativo de teste também precisa do pacote Microsoft.Testing.Extensions.TrxReport para criar relatórios.
O recurso separa o suporte da ativação:
- Retorne
truedeIsSupportedquando seu framework puder fornecer metadados TRX. - Em
Enable(), registre que o repórter TRX solicitou os metadados. O reporter chama esse método no início de uma sessão de teste quando os relatórios TRX estão habilitados. - Após a ativação, adicione as propriedades TRX aos nós de teste que seu framework publica.
A funcionalidade a seguir armazena o estado de ativação. Os projetos de exemplo têm como destino .NET 10 e fazem referência ao MTP 2.5.1:
internal sealed class TrxCapability : ITrxReportCapability
{
public bool IsSupported => true;
public bool IsEnabled { get; private set; }
public void Enable() => IsEnabled = true;
}
Friend NotInheritable Class TrxCapability
Implements ITrxReportCapability
Public ReadOnly Property IsSupported As Boolean Implements ITrxReportCapability.IsSupported
Get
Return True
End Get
End Property
Public Property IsEnabled As Boolean
Get
Return _isEnabled
End Get
Private Set(value As Boolean)
_isEnabled = value
End Set
End Property
Private _isEnabled As Boolean
Public Sub Enable() Implements ITrxReportCapability.Enable
IsEnabled = True
End Sub
End Class
Retorne a capacidade do capabilitiesFactory que você passa para RegisterTestFramework. Dê ao framework a mesma instância de capacidade para que ele possa observar Enable(). Para um aplicativo de teste composto manualmente, registre o provedor TRX após sua estrutura e outras extensões:
var trxCapability = new TrxCapability();
var builder = await TestApplication.CreateBuilderAsync(args);
builder.RegisterTestFramework(
_ => new TestFrameworkCapabilities(trxCapability),
(_, _) => new ReportFramework(trxCapability));
builder.AddTrxReportProvider();
Dim trxCapability As New TrxCapability()
Dim builder = Await TestApplication.CreateBuilderAsync(args)
builder.RegisterTestFramework(
Function(services) New TestFrameworkCapabilities(trxCapability),
Function(capabilities, services) New ReportFramework(trxCapability))
builder.AddTrxReportProvider()
O pacote de abstração fornece propriedades tipadas para TestNode.Properties:
| Property | Purpose |
|---|---|
TrxFullyQualifiedTypeNameProperty |
Fornece o nome da classe de teste totalmente qualificado. |
TrxCategoriesProperty |
Fornece as categorias do teste. |
TrxExceptionProperty |
Fornece a mensagem de falha e o rastreamento de pilha. |
TrxMessagesProperty |
Contém as entradas StandardOutputTrxMessage, StandardErrorTrxMessage e DebugOrTraceTrxMessage. |
TrxTestDefinitionName |
Substitui o nome da definição de teste no relatório. |
TrxWorkItemsProperty |
Fornece identificadores de item de trabalho. |
Por exemplo, enriqueça um resultado depois que seu framework determinar o resultado do teste:
if (trxCapability.IsEnabled)
{
testNode.Properties.Add(
new TrxFullyQualifiedTypeNameProperty("Contoso.CalculatorTests"));
testNode.Properties.Add(new TrxCategoriesProperty(["Unit"]));
testNode.Properties.Add(new TrxMessagesProperty(
[new StandardOutputTrxMessage($"Captured output for {test.Name}.")]));
if (failure is not null)
{
testNode.Properties.Add(
new TrxExceptionProperty(failure.Message, failure.StackTrace));
}
}
If _trxCapability.IsEnabled Then
testNode.Properties.Add(
New TrxFullyQualifiedTypeNameProperty("Contoso.CalculatorTests"))
testNode.Properties.Add(New TrxCategoriesProperty({"Unit"}))
testNode.Properties.Add(New TrxMessagesProperty(
{New StandardOutputTrxMessage($"Captured output for {test.Name}.")}))
If failure IsNot Nothing Then
testNode.Properties.Add(
New TrxExceptionProperty(failure.Message, failure.StackTrace))
End If
End If
Essas propriedades complementam o estado de nó de teste necessário; elas não o substituem. As mensagens específicas do TRX também não substituem StandardOutputProperty e StandardErrorProperty da plataforma.
O exemplo completo contém um teste bem-sucedido e um teste com falha intencional. Com --report-trxele grava os resultados e os metadados enriquecidos em um arquivo TRX e retorna o código 2de saída. Para executar apenas o teste aprovado, adicione --filter-uid trx.pass.
Se a funcionalidade estiver ausente ou IsSupported estiver false, o repórter TRX avisará que o framework não dá suporte ao enriquecimento TRX. O repórter ainda pode criar um relatório com base nos dados disponíveis, mas os detalhes específicos do framework podem estar ausentes. Não anuncie suporte a menos que sua estrutura forneça os metadados correspondentes.
IGracefulStopTestExecutionCapability
Para dar suporte a --maximum-failed-tests em uma estrutura de teste personalizada, implemente Microsoft.Testing.Platform.Capabilities.TestFramework.IGracefulStopTestExecutionCapability. A funcionalidade faz parte do pacote Microsoft.Testing.Platform e está disponível a partir do MTP 1.5. Os autores de teste que usam uma estrutura que já dá suporte à opção não precisam implementar a funcionalidade.
A interface define Task StopTestExecutionAsync(CancellationToken cancellationToken). Quando a contagem de falhas atinge o máximo solicitado, o MTP chama esse método. Sua implementação deve informar a estrutura para interromper o agendamento de novos testes, enquanto permite que os testes que já foram iniciados sejam concluídos, executem a limpeza e publiquem seus resultados.
Importante
A funcionalidade e o auxiliar AddMaximumFailedTestsService são APIs experimentais que produzem diagnósticos do compilador TPEXP. Seus contratos podem ser alterados ou removidos. Os projetos de exemplo suprimem TPEXP explicitamente.
Siga estes requisitos ao implementar a funcionalidade:
- Compartilhe o estado de parada entre a funcionalidade e o agendador de teste do framework. Apenas retornar uma tarefa concluída não interrompe os testes.
- Torne as solicitações de parada thread-safe e idempotentes. Mais de um componente de plataforma pode solicitar a interrupção.
- Retorne após sinalizar a parada. Não aguarde até que toda a execução ou o barramento de mensagens seja concluído: o MTP pode chamar o método enquanto processa um resultado de teste, pois essa espera pode causar um deadlock.
- Mantenha o estado de parada controlada separado do cancelamento da solicitação. Não encerre o processo nem cancele a publicação de resultados para implementar uma interrupção controlada. Honre o token de cancelamento do método se a operação de parada exigir trabalho assíncrono.
- Após a conclusão dos testes ativos, conclua o ciclo de vida normal da solicitação, incluindo a publicação de resultados, a limpeza e a chamada para
ExecuteRequestContext.Complete().
A implementação a seguir usa um sinalizador thread-safe. Em seu framework, verifique IsStopRequested antes de agendar cada teste e pare de aceitar novo trabalho quando o sinalizador for true.
public sealed class GracefulStopCapability : IGracefulStopTestExecutionCapability
{
private int _stopRequested;
public bool IsStopRequested => Volatile.Read(ref _stopRequested) != 0;
public Task StopTestExecutionAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
Interlocked.Exchange(ref _stopRequested, 1);
return Task.CompletedTask;
}
}
Public NotInheritable Class GracefulStopCapability
Implements IGracefulStopTestExecutionCapability
Private _stopRequested As Integer
Public ReadOnly Property IsStopRequested As Boolean
Get
Return Volatile.Read(_stopRequested) <> 0
End Get
End Property
Public Function StopTestExecutionAsync(cancellationToken As CancellationToken) As Task _
Implements IGracefulStopTestExecutionCapability.StopTestExecutionAsync
cancellationToken.ThrowIfCancellationRequested()
Interlocked.Exchange(_stopRequested, 1)
Return Task.CompletedTask
End Function
End Class
Expor a capacidade por meio de ITestFrameworkCapabilities.Capabilities. O exemplo de registro usa a coleção do TestFrameworkCapabilities MTP.
Durante o registro do framework de teste, passe a instância de capability registrada para seu framework. O auxiliar a seguir aceita sua fábrica de framework e um IExtension que possui a opção de linha de comando. Ele também chama AddMaximumFailedTestsService do Microsoft.Testing.Platform.Helpers namespace para registrar o provedor de opção --maximum-failed-tests . Sem esse provedor, o MTP não reconhece a opção.
public static void Register(
ITestApplicationBuilder builder,
IExtension owner,
Func<GracefulStopCapability, ITestFramework> createFramework)
{
builder.RegisterTestFramework(
_ => new TestFrameworkCapabilities(new GracefulStopCapability()),
(capabilities, _) => createFramework(
capabilities.Capabilities.OfType<GracefulStopCapability>().Single()));
builder.AddMaximumFailedTestsService(owner);
}
Public Sub Register(
builder As ITestApplicationBuilder,
owner As IExtension,
createFramework As Func(Of GracefulStopCapability, ITestFramework))
builder.RegisterTestFramework(
Function(services) New TestFrameworkCapabilities(New GracefulStopCapability()),
Function(capabilities, services) createFramework(
capabilities.Capabilities.OfType(Of GracefulStopCapability)().Single()))
builder.AddMaximumFailedTestsService(owner)
End Sub
A fábrica de recursos cria um novo estado de parada e a fábrica de framework recupera essa mesma instância. Não crie uma segunda capacidade desconectada em seu framework. Para frameworks que dão suporte a várias solicitações de execução, mantenha o estado de parada no escopo da execução correspondente. Não remova uma solicitação de parada aceita quando a execução for iniciada.
O MTP rejeita --maximum-failed-tests durante a validação da linha de comando se o provedor de opções estiver registrado, mas o framework não expuser essa capacidade. Quando o limite de falha dispara uma parada, o MTP retorna o código 13de saída. A contagem final de falhas pode exceder o limite porque o processamento de resultados é assíncrono e os testes podem já estar em andamento.
Para saber o contrato da interface, consulte o código-fonte IGracefulStopTestExecutionCapability.