Unidad que prueba métodos internos en la biblioteca VS2017 .Net Standard

150

Actualmente estoy jugando con el último candidato de lanzamiento de Visual Studio 2017 creando una biblioteca .Net Standard 1.6. Estoy usando xUnit para probar mi código y me preguntaba si aún puede probar métodos internos en VS2017.

Recuerdo que podría tener toda una línea clase AssemblyInfo.cs en VS2015 que permitiría que proyectos específicos vean métodos internos

[assembly:InternalsVisibleTo("MyTests")]

Como no hay una clase AssemblyInfo.cs en los proyectos VS2017 .Net Standard, me preguntaba si aún puede probar los métodos internos de la unidad.

Phil Murray
fuente
3
Usted debe ser capaz de probar la unidad su código de funcionalidad visible desde el exterior solo. Después de todo, si ninguna ruta lógica desde el código externo puede alcanzar esos métodos internos, ¿qué estarían haciendo allí en primer lugar?
David
3
@David Puedo y he hecho esto, pero anteriormente he puesto pruebas unitarias simples alrededor de algunas clases internas. Solo para ser más explícito en las pruebas.
Phil Murray
55
AFAIK, puede colocar este atributo en cualquier otro archivo, fuera del namespacebloque, y debe compilarse. No debería haber nada mágico al respecto AssemblyInfo.cs. No funciona? Por supuesto, debe agregar la usingcláusula correcta o usar el atributo totalmente calificado [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Something")].
Groo
1
@David Si está creando una biblioteca con clases internas y necesita probar y burlarse de estas clases, InternalsVisibleToes crítico, por ejemplo, aquí - stackoverflow.com/a/17574183/43453
PandaWood

Respuestas:

210

Según los documentos de .NET paraInternalsVisibleToAttribute :

El atributo se aplica a nivel de ensamblaje. Esto significa que se puede incluir al comienzo de un archivo de código fuente, o se puede incluir en el archivo AssemblyInfo en un proyecto de Visual Studio.

En otras palabras, simplemente puede colocarlo en su propio archivo .cs nombrado arbitrariamente, y debería funcionar bien:

// some .cs file included in your project
using System.Runtime.CompilerServices;
[assembly:InternalsVisibleTo("MyTests")]
Groo
fuente
1
@PhilMurray: también, parece que hay una configuración que debería permitirle crear un AssemblyInfo.csarchivo "clásico" como se explica aquí . De lo contrario, todos los atributos como "descripción", "copyright" y otras cosas se almacenan dentro del archivo .csproj.
Groo
43

Como se describe aquí:

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

Es posible agregar el atributo visible interno dentro del archivo del proyecto agregando otro ItemGroup:

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

o incluso:

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

Me gusta esa solución porque el archivo del proyecto parece ser el lugar adecuado para definir tales preocupaciones.

JanDotNet
fuente
8

Si bien la primera respuesta está perfectamente bien. Si todavía desea hacer esto en el original AssemblyInfo, siempre puede elegir no generar automáticamente el archivo y agregarlo manualmente.

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

Para más información: https://stackoverflow.com/a/47075759/869033

Nick N.
fuente
5

El atributo "InternalsVisibleTo" es clave para cualquier tipo de prueba de "caja blanca" (el término de la década, supongo) para .Net. Se puede colocar en cualquier archivo C # con el atributo "ensamblado" en el frente. Tenga en cuenta que los MS DOC dicen que el nombre del ensamblado debe ser calificado por el token de clave pública, si está firmado. A veces eso no funciona y uno debe usar la clave pública completa en su lugar. El acceso a componentes internos es clave para probar sistemas concurrentes y en muchas otras situaciones. Ver https://www.amazon.com/xUnit-Test-Patterns-Refactoring-Code/dp/0131495054 . En este libro, Meszaros describe una variedad de estilos de codificación que básicamente constituyen un enfoque de "Diseño para prueba" para el desarrollo de programas. Al menos así lo he usado a lo largo de los años.

AGREGADO: Lo siento, no he estado aquí por un tiempo. Un enfoque es llamado el enfoque de "subclase de prueba" por Meszaros. Nuevamente, uno tiene que usar "internalsvisableto" para acceder a los componentes internos de la clase base. Esta es una gran solución, pero no funciona para clases selladas. Cuando enseño "Design For Test", sugiero que es una de las cosas que se deben "pre-diseñar" en las clases base para proporcionar capacidad de prueba. Tiene que convertirse en algo casi cultural. Diseñe una clase base "base" que no esté sellada. Llámelo UnsealedBaseClass o algo uniformemente reconocible. Esta es la clase que se subclasificará para la prueba. También se subclasifica para construir la clase sellada de producción, que a menudo solo difiere en los constructores que expone. Trabajo en la industria nuclear y los requisitos de prueba se toman MUY en serio. Entonces, tengo que pensar en estas cosas todo el tiempo. Por cierto, dejar los ganchos de prueba en el código de producción no se considera un problema en nuestro campo, siempre y cuando sean "internos" en una implementación .Net. Las ramificaciones de NO probar algo pueden ser bastante profundas.

kurt.matis
fuente
1

Otra forma es usar una clase pública 'wrapper' TestMyFoo dentro del proyecto de destino que tiene métodos públicos e inherentes de la clase que necesita probar (por ejemplo, MyFoo). Estos métodos públicos simplemente llaman a la clase base que desea probar.

No es 'ideal' ya que terminas enviando un gancho de prueba en tu proyecto de destino. Pero tenga en cuenta que los automóviles modernos y confiables se envían con puertos de diagnóstico y los dispositivos electrónicos confiables modernos se envían con una conexión JTAG. Pero nadie es tan tonto como para conducir su automóvil usando el puerto de diagnóstico.

Andrew Paté
fuente