Métodos internos de teste de unidade na biblioteca VS2017 .Net Standard


150

Atualmente, estou brincando com o candidato mais recente do Visual Studio 2017, criando uma biblioteca .Net Standard 1.6. Estou usando o xUnit para testar meu código de unidade e queria saber se você ainda pode testar métodos internos no VS2017.

Lembro-me de que era possível criar uma classe AssemblyInfo.cs no VS2015 que permitisse que projetos especificados vissem métodos internos

[assembly:InternalsVisibleTo("MyTests")]

Como não há classe AssemblyInfo.cs nos projetos VS2017 .Net Standard, eu queria saber se você ainda pode testar métodos internos de unidade?


3
Você deve poder testar seu código unicamente com a funcionalidade visível externamente. Afinal, se nenhum caminho lógico do código externo puder alcançar esses métodos internos, o que eles estariam fazendo lá em primeiro lugar?
David

3
@ David Eu posso e já fiz isso, mas coloquei testes de unidade simples em torno de algumas classes internas anteriormente. Apenas para ser mais explícito nos testes.
Phil Murray

5
AFAIK, você pode colocar esse atributo em qualquer outro arquivo, fora do namespacebloco, e ele deve ser compilado. Não deveria haver nada de mágico AssemblyInfo.cs. Isso não funciona? Obviamente, você precisa adicionar a usingcláusula correta ou usar o atributo totalmente qualificado [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Something")].
Groo

1
@ David Se você estiver criando uma biblioteca com classes internas e você precisa de teste e zombar dessas classes, InternalsVisibleToé fundamental - por exemplo aqui - stackoverflow.com/a/17574183/43453
PandaWood

Respostas:


210

De acordo com os documentos do .NET para oInternalsVisibleToAttribute :

O atributo é aplicado no nível da montagem. Isso significa que ele pode ser incluído no início de um arquivo de código-fonte ou no arquivo AssemblyInfo em um projeto do Visual Studio.

Em outras palavras, você pode simplesmente colocá-lo em seu próprio arquivo .cs nomeado arbitrariamente e deve funcionar bem:

// some .cs file included in your project
using System.Runtime.CompilerServices;
[assembly:InternalsVisibleTo("MyTests")]

1
@ PhilMurray: também, parece que existe uma configuração que deve permitir que você crie um AssemblyInfo.csarquivo "clássico", como explicado aqui . Caso contrário, todos os atributos como "descrição", "direitos autorais" e outras coisas serão armazenados dentro do arquivo .csproj.
Groo

43

Conforme descrito aqui:

https://blog.sanderaernouts.com/make-internals-visible-with-new-csproj-format

É possível adicionar o atributo visível interno ao arquivo do projeto adicionando outro ItemGroup:

<ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
        <_Parameter1>$(AssemblyName).Tests</_Parameter1>
    </AssemblyAttribute>
</ItemGroup>

ou até:

<ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
        <_Parameter1>$(MSBuildProjectName).Tests</_Parameter1>
    </AssemblyAttribute>
</ItemGroup>

Gosto dessa solução porque o arquivo do projeto parece ser o local certo para definir essas preocupações.


8

Enquanto a primeira resposta está perfeitamente bem. Se você ainda deseja fazer isso no original, AssemblyInfopode sempre optar por não gerar automaticamente o arquivo e adicioná-lo manualmente.

<PropertyGroup>
   <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>

Para mais informações: https://stackoverflow.com/a/47075759/869033


5

O atributo "InternalsVisibleTo" é essencial para qualquer tipo de teste de "caixa branca" (o termo da década, eu acho) para o .Net. Ele pode ser colocado em qualquer arquivo c # com o atributo "assembly" na frente. Observe que os DOCs da Microsoft dizem que o nome do assembly deve ser qualificado pelo token de chave pública, se estiver assinado. Às vezes isso não funciona e é preciso usar a chave pública completa no local. O acesso a componentes internos é essencial para testar sistemas concorrentes e em muitas outras situações. Consulte https://www.amazon.com/xUnit-Test-Patterns-Refactoring-Code/dp/0131495054 . Neste livro, Meszaros descreve uma variedade de estilos de codificação que basicamente constituem uma abordagem "Design For Test" para o desenvolvimento de programas. Pelo menos é assim que eu tenho usado ao longo dos anos.

ADICIONADO: Desculpe, não estou aqui há um tempo. Uma abordagem é chamada de "subclasse de teste" por Meszaros. Novamente, é preciso usar "internalsvisableto" para acessar os internos da classe base. Essa é uma ótima solução, mas não funciona para classes seladas. Quando ensino o "Design For Test", sugiro que seja uma das coisas que devem ser "pré-projetadas" nas classes base para fornecer testabilidade. Tem que se tornar quase uma coisa cultural. Crie uma classe base "base" que não esteja lacrada. Chame-o de UnsealedBaseClass ou algo uniformemente reconhecível. Esta é a classe a ser subclassificada para teste. Também é subclassificado para construir a classe de produção selada, que geralmente difere apenas nos construtores que expõe. Eu trabalho na indústria nuclear e os requisitos de teste são levados muito a sério. Então, eu tenho que pensar sobre essas coisas o tempo todo. A propósito, deixar ganchos de teste no código de produção não é considerado um problema em nosso campo, desde que sejam "internos" em uma implementação .Net. As ramificações de NÃO testar algo podem ser bastante profundas.


1

Outra maneira é usar uma classe pública TestMyFoo 'wrapper' dentro do projeto de destino que possui métodos públicos e heranças da classe que você precisa testar (por exemplo, MyFoo). Esses métodos públicos simplesmente chamam a classe base que você deseja testar.

Não é 'ideal', pois você acaba enviando um gancho de teste em seu projeto de destino. Mas considere carros modernos e confiáveis ​​com portas de diagnóstico e equipamentos eletrônicos modernos e modernos com uma conexão JTAG. Mas ninguém é bobo o suficiente para dirigir seu carro usando a porta de diagnóstico.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.