Partilhar via


Geração de código, compilação e convenções de nomenclatura no Microsoft Fakes

Este artigo discute opções e problemas na geração e compilação de código Fakes e descreve as convenções de nomenclatura para tipos, membros e parâmetros gerados por Fakes.

Requisitos

  • Visual Studio Enterprise

  • Um projeto .NET Framework

  • O suporte a projetos no estilo .NET Core, .NET 5.0 ou posterior foi pré-visualizado no Visual Studio 2019 Atualização 6 e configurado por padrão na Atualização 8. Para obter mais informações, consulte Microsoft Fakes for .NET Core and SDK-style projects.

Geração e compilação de código

Configurar a geração de código de stubs

A geração de tipos de stub é configurada num arquivo XML que tem a extensão .fakes. A estrutura Fakes integra-se no processo de compilação através de tarefas personalizadas do MSBuild e deteta esses arquivos no momento da compilação. O gerador de código Fakes compila os tipos de stub em um assembly e adiciona a referência ao projeto.

O exemplo a seguir ilustra os tipos de stub definidos em FileSystem.dll:

<Fakes xmlns="http://schemas.microsoft.com/fakes/2011/">
    <Assembly Name="FileSystem"/>
</Fakes>

Filtragem de tipos

Os filtros podem ser definidos no arquivo .fakes para restringir quais tipos devem ser cortados. Você pode adicionar um número ilimitado de elementos Clear, Add, Remove sob o elemento StubGeneration para criar a lista de tipos selecionados.

Por exemplo, o seguinte arquivo .fakes gera stubs para tipos nos namespaces System e System.IO, mas exclui qualquer tipo que contenha "Handle" no System:

<Fakes xmlns="http://schemas.microsoft.com/fakes/2011/">
  <Assembly Name="mscorlib" />
  <!-- user code -->
  <StubGeneration>
    <Clear />
    <Add Namespace="System!" />
    <Add Namespace="System.IO!"/>
    <Remove TypeName="Handle" />
  </StubGeneration>
  <!-- /user code -->
</Fakes>

As cadeias de caracteres de filtro usam uma gramática simples para definir como a correspondência deve ser feita:

  • Os filtros não diferenciam maiúsculas de minúsculas por padrão; Os filtros executam uma correspondência de substring:

    el corresponde a "olá"

  • Adicionar ! ao final do filtro faz com que ele faça uma correspondência precisa que diferencia maiúsculas de minúsculas:

    el! não corresponde a "olá"

    hello! corresponde a "olá"

  • Adicionar * ao final do filtro faz com que ele corresponda ao prefixo da cadeia de caracteres:

    el* não corresponde a "olá"

    he* corresponde a "olá"

  • Vários filtros em uma lista separada por ponto-e-vírgula são combinados como uma disjunção:

    el;wo corresponde a "olá" e "mundo"

Classes concretas de stub e métodos virtuais

Por padrão, os tipos de stub são gerados para todas as classes não seladas. É possível restringir os tipos de stub a classes abstratas através do arquivo de configuração .fakes :

<Fakes xmlns="http://schemas.microsoft.com/fakes/2011/">
  <Assembly Name="mscorlib" />
  <!-- user code -->
  <StubGeneration>
    <Types>
      <Clear />
      <Add AbstractClasses="true"/>
    </Types>
  </StubGeneration>
  <!-- /user code -->
</Fakes>

Tipos internos

O gerador de código Fakes gera tipos de shim e tipos de stub para os tipos que são visíveis ao assembly Fakes gerado. Para tornar os tipos internos de um assembly shimmed visíveis para o Fakes e o seu assembly de teste, adicione atributos InternalsVisibleToAttribute ao código do assembly shimmed que dá visibilidade ao assembly Fakes gerado e ao assembly de teste. Aqui está um exemplo:

// FileSystem\AssemblyInfo.cs
[assembly: InternalsVisibleTo("FileSystem.Fakes")]
[assembly: InternalsVisibleTo("FileSystem.Tests")]

Tipos internos em assemblies fortemente nomeados

Se o assembly shimmed tiver um nome forte e você quiser acessar os tipos internos do assembly:

  • Tanto o assembly de teste quanto o assembly Fakes devem ter um nome forte.

  • Adicione as chaves públicas do assembly test e Fakes aos atributos InternalsVisibleToAttribute nos assemblies shimmed. Veja como os atributos de exemplo no código de assembly shimmed ficariam quando o assembly shimmed fosse fortemente nomeado:

    // FileSystem\AssemblyInfo.cs
    [assembly: InternalsVisibleTo("FileSystem.Fakes",
        PublicKey=<Fakes_assembly_public_key>)]
    [assembly: InternalsVisibleTo("FileSystem.Tests",
        PublicKey=<Test_assembly_public_key>)]
    

Se o assembly shimmed for fortemente nomeado, a estrutura Fakes assina automaticamente fortemente o assembly Fakes gerado. Você tem que realizar uma assinatura forte na montagem de teste. Consulte Strong-Named assemblies.

A estrutura Fakes usa a mesma chave para assinar todos os assemblies gerados, podendo usar este trecho como ponto de partida para adicionar o atributo InternalsVisibleTo ao assembly fakes no seu código de assembly ajustado.

[assembly: InternalsVisibleTo("FileSystem.Fakes, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e92decb949446f688ab9f6973436c535bf50acd1fd580495aae3f875aa4e4f663ca77908c63b7f0996977cb98fcfdb35e05aa2c842002703cad835473caac5ef14107e3a7fae01120a96558785f48319f66daabc862872b2c53f5ac11fa335c0165e202b4c011334c7bc8f4c4e570cf255190f4e3e2cbc9137ca57cb687947bc")]

Você pode especificar uma chave pública diferente para o assembly Fakes, como uma chave criada para o assembly shimmed, especificando o caminho completo para o arquivo .snk que contém a chave alternativa como o KeyFile valor do atributo noFakes\Compilationelemento do arquivo .fakes. Por exemplo:

<-- FileSystem.Fakes.fakes -->
<Fakes ...>
  <Compilation KeyFile="full_path_to_the_alternate_snk_file" />
</Fakes>

Em seguida, você precisa usar a chave pública do arquivo .snk alternativo como o segundo parâmetro do atributo InternalVisibleTo para o assembly Fakes no código de assembly shimmed:

// FileSystem\AssemblyInfo.cs
[assembly: InternalsVisibleTo("FileSystem.Fakes",
    PublicKey=<Alternate_public_key>)]
[assembly: InternalsVisibleTo("FileSystem.Tests",
    PublicKey=<Test_assembly_public_key>)]

No exemplo acima, os valores Alternate_public_key e o Test_assembly_public_key podem ser os mesmos.

Otimize os tempos de construção

A compilação de assemblies Fakes pode aumentar significativamente seu tempo de compilação. Você pode minimizar o tempo de compilação gerando os assemblies Fakes para assemblies do sistema .NET e assemblies de terceiros em um projeto centralizado separado. Como essas montagens raramente mudam em sua máquina, você pode reutilizar as montagens Fakes geradas em outros projetos.

Nos seus projetos de teste de unidade, adicione uma referência aos assemblies Fakes compilados que estão localizados em FakesAssemblies na pasta do projeto.

  1. Crie uma nova biblioteca de classes com a versão de tempo de execução do .NET correspondente aos seus projetos de teste. Vamos dar-lhe o nome de Fakes.Prebuild. Remova o arquivo class1.cs do projeto, não necessário.

  2. Adicione referência a todos os assemblies de sistema e de terceiros para os quais você precisa de falsificações.

  3. Adicione um ficheiro .fakes para cada um dos assemblies e construa.

  4. Do seu projeto de teste

    • Certifique-se de que você tem uma referência para a DLL de tempo de execução Fakes:

      %ProgramFiles(x86)%\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\PublicAssemblies\Microsoft.QualityTools.Testing.Fakes.dll

    • Para cada assembly para o qual você criou Fakes, adicione uma referência ao arquivo DLL correspondente na pasta Fakes.Prebuild\FakesAssemblies do seu projeto.

Evite o conflito de nomes de assemblies

Em um ambiente Team Build, todas as saídas de compilação são mescladas em um único diretório. Se vários projetos usarem Fakes, pode acontecer que assemblies de Fakes de versões diferentes substituam-se uns aos outros. Por exemplo, o TestProject1 simula mscorlib.dll do .NET Framework 2.0 e o TestProject2 simula mscorlib.dll para o .NET Framework 4, ambos resultando em um assembly mscorlib.Fakes.dll Fakes.

Para evitar esse problema, os Fakes devem criar automaticamente nomes de assembly Fakes qualificados de versão para referências que não sejam de projeto ao adicionar os arquivos .fakes . Um nome de assembly Fakes qualificado para versão incorpora um número de versão quando você cria o nome de assembly Fakes:

Dado um assembly MyAssembly e uma versão 1.2.3.4, o nome do assembly Fakes é MyAssembly.1.2.3.4.Fakes.

Você pode alterar ou remover esta versão editando o atributo Version do elemento Assembly no .fakes:

attribute of the Assembly element in the .fakes:
<Fakes ...>
  <Assembly Name="MyAssembly" Version="1.2.3.4" />
  ...
</Fakes>

Convenções de nomenclatura falsas

Convenções de nomenclatura de tipos de calço e de tipos de stub

Namespaces

  • . O sufixo Fakes é adicionado ao namespace.

    Por exemplo, System.Fakes namespace contém os tipos shim do namespace System.

  • Global.Fakes contém o tipo shim do namespace vazio.

    Nomes dos tipos

  • O prefixo Shim é adicionado ao nome do tipo para criar o nome do tipo shim.

    Por exemplo, ShimExample é o tipo shim do tipo Example.

  • O prefixo do stub é adicionado ao nome do tipo para formar o nome de tipo de stub.

    Por exemplo, StubIExample é o tipo de stub do tipo IExample.

    Argumentos de tipo e estruturas de tipo aninhadas

  • Os argumentos de tipo genéricos são copiados.

  • A estrutura de tipo aninhada é copiada para tipos de calço.

Convenções de nomenclatura para propriedades de delegado shim ou campos de delegado stub

Regras básicas para nomear campos, a partir de um nome vazio:

  • O nome do método é acrescentado.

  • Se o nome do método for uma implementação de interface explícita, os pontos serão removidos.

  • Se o método for genérico, Ofn é acrescentado onde n é o número de argumentos genéricos do método.

    Nomes de métodos especiais , como getter ou setters de propriedade, são tratados conforme descrito na tabela a seguir:

Se o método é... Example Nome do método anexado
Um construtor .ctor Constructor
Um construtor estático .cctor StaticConstructor
Um acessador com nome de método composto por duas partes separadas por "_" (como acessores de propriedade) kind_name (caso comum, mas não aplicado pela ECMA) NameKind, onde ambas as partes foram capitalizadas e trocadas
Método acessor de propriedade Prop PropGet
Ajustador de propriedade Prop PropSet
Adicionador de eventos Add
Removedor de eventos Remove
Um operador composto por duas partes op_name NameOp
Por exemplo: + operador op_Add AddOp
Para um operador de conversão, o tipo de retorno é acrescentado. T op_Implicit ImplicitOpT

Observação

  • Getters e setters de indexadores são tratados de forma semelhante às propriedades. O nome padrão para um indexador é Item.
  • Os nomes dos tipos de parâmetros são transformados e concatenados.
  • O tipo de retorno é ignorado, a menos que haja uma ambiguidade de sobrecarga. Se houver uma ambiguidade de sobrecarga, o tipo de retorno será anexado no final do nome.

Convenções de nomenclatura de tipo de parâmetro

Dado A cadeia de caracteres anexada é...
Um tipoT T

O namespace, a estrutura aninhada e os tiques genéricos são descartados.
Um parâmetro outout T TOut
Um parâmetro refref T TRef
Um tipo de matrizT[] TArray
Um tipo de matriz multidimensionalT[ , , ] T3
Um tipo de ponteiroT* TPtr
Um tipo genéricoT<R1, ...> TOfR1
Um argumento!i de tipo genérico de tipo C<TType> Ti
Um argumento de tipo genérico!!i do método M<MMethod> Mi
Um tipo aninhadoN.T N é acrescentado, em seguida, T

Regras recursivas

As seguintes regras são aplicadas recursivamente:

  • Como Fakes usa C# para gerar os assemblies Fakes, qualquer caractere que produza um token C# inválido é escapado para "_" (sublinhado).

  • Se um nome resultante entrar em conflito com qualquer membro do tipo declarante, um esquema de numeração é usado anexando um contador de dois dígitos, começando em 01.

Utilização de Microsoft Fakes na Integração Contínua

Geração de montagem Microsoft Fakes

Microsoft Fakes é um recurso disponível exclusivamente no Visual Studio Enterprise. Como tal, a geração de Fakes Assemblies requer o uso da tarefa de compilação do Visual Studio ao criar seu projeto.

Observação

Uma estratégia alternativa envolve verificar seus Fakes Assemblies diretamente no sistema de Integração Contínua (CI) e utilizar a Tarefa MSBuild. Se você optar por essa abordagem, precisará incluir uma referência de assembly para o assembly Fakes gerado em seu projeto de teste, conforme mostrado no seguinte trecho de código:

<Project Sdk="Microsoft.NET.Sdk">
    <ItemGroup>
        <Reference Include="FakesAssemblies\System.Fakes.dll"/>
    </ItemGroup>
</Project>

Essa referência deve ser adicionada manualmente, especificamente para projetos no estilo SDK (ou seja, .NET Core, .NET 5+ e .NET Framework), porque esses projetos agora adicionam implicitamente referências de assembly. Se você decidir usar esse método, certifique-se de atualizar o assembly Fakes sempre que o assembly pai sofrer alterações.