166 votes

Rendre le code interne mais disponible pour les tests unitaires d'autres projets

Nous mettons tous nos tests unitaires dans leurs propres projets. Nous constatons que nous devons rendre certaines classes publiques au lieu d'internes juste pour les tests unitaires. Existe-t-il un moyen d'éviter d'avoir à le faire ? Quelles sont les conséquences pour la mémoire de rendre les classes publiques au lieu de scellées ?

2 votes

242voto

Ash Points 31541

Si vous utilisez .NET, le InternalsVisibleTo L'attribut assembly vous permet de créer des assemblages "amis". Il s'agit d'assemblages spécifiques fortement nommés qui sont autorisés à accéder aux classes internes et aux membres de l'autre assemblage.

Notez que cette option doit être utilisée avec discernement car elle permet de coupler étroitement les assemblages concernés. Une utilisation courante de InternalsVisibleTo est pour les projets de tests unitaires. Ce n'est probablement pas un bon choix pour une utilisation dans les assemblages de votre application réelle, pour la raison indiquée ci-dessus.

Ejemplo:

[assembly: InternalsVisibleTo("NameAssemblyYouWantToPermitAccess")]
namespace NameOfYourNameSpace
{

27 votes

Je vous suggère de mettre un #if DEBUG autour de l'attribut, puis de faire des tests unitaires en debug. De cette façon, vous serez sûr que l'attribut n'est pas défini dans le code de la version.

0 votes

C'est juste une idée, je ne sais pas.... Pourquoi pas ? #if DEBUG public class IniReader #else internal class IniReader #endif Probablement pas recommandé ? Pourquoi ?

12 votes

Pourquoi limiter les tests aux constructions de débogage ?

23voto

babula pradhan Points 11

Vous trouverez ci-dessous des exemples d'utilisation de l'in .NET Core applications.

  1. Ajouter AssemblyInfo.cs et ajouter [assembly: InternalsVisibleTo("AssemblytoVisible")]
  2. Ajouter ceci dans .csproj fichier (le projet qui contient les classes internes)

    <ItemGroup> <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo"> <_Parameter1>Test_Project_Name</_Parameter1> <!-- The name of the project that you want the Internal class to be visible To it --> </AssemblyAttribute> </ItemGroup>

Pour plus d'informations, veuillez suivre https://improveandrepeat.com/2019/12/how-to-test-your-internal-classes-in-c/

4voto

Josh Points 23923

S'il s'agit d'une classe interne, elle ne doit pas être utilisée de manière isolée. Par conséquent, vous ne devriez pas vraiment la tester, sauf si vous testez une autre classe qui utilise cet objet en interne.

Tout comme vous ne devriez pas tester les membres privés d'une classe, vous ne devriez pas tester les classes internes d'une DLL. Ces classes sont des détails d'implémentation d'une classe accessible au public, et doivent donc être testées par d'autres tests unitaires.

L'idée est que vous ne voulez tester que le comportement d'une classe car si vous testez les détails de l'implémentation interne, vos tests seront fragiles. Vous devez pouvoir modifier les détails de l'implémentation de n'importe quelle classe sans casser tous vos tests.

Si vous vous rendez compte que vous avez vraiment besoin de tester cette classe, vous devriez peut-être réexaminer la raison pour laquelle cette classe est interne en premier lieu.

2 votes

Les détails de mise en œuvre doivent être exercés dans le cadre d'un test global. Ne regardez pas les variables privées... testez le comportement attendu. Si le test est bon... toute la plomberie interne et le câblage doivent être testés dans le cadre du test. Voté en haut.

78 votes

Je ne suis pas nécessairement d'accord avec cela car ces classes sont "publiques" pour les autres classes de la DLL et la fonctionnalité de la classe doit être testée indépendamment.

33 votes

Je ne suis pas non plus d'accord. Les unités sont des unités et elles doivent être testées de manière isolée.

4voto

ktutnik Points 1711

À des fins de documentation

Alternativement, vous pouvez instancier une classe interne en utilisant la fonction Type.GetType méthode

exemple

//IServiceWrapper is public class which is 
//the same assembly with the internal class 
var asm = typeof(IServiceWrapper).Assembly;
//Namespace.ServiceWrapper is internal
var type = asm.GetType("Namespace.ServiceWrapper");
return (IServiceWrapper<T>)Activator
    .CreateInstance(type, new object[1] { /*constructor parameter*/ });

Pour le type générique, il y a différents processus comme ci-dessous :

var asm = typeof(IServiceWrapper).Assembly;
//note the name Namespace.ServiceWrapper`1
//this is for calling Namespace.ServiceWrapper<>
var type = asm.GetType("Namespace.ServiceWrapper`1");
var genType = type.MakeGenericType(new Type[1] { typeof(T) });
return (IServiceWrapper<T>)Activator
     .CreateInstance(genType, new object[1] { /*constructor parameter*/});

-6voto

TraumaPony Points 6635

Les classes peuvent être à la fois publiques ET scellées.

Mais, ne faites pas ça.

Vous pouvez créer un outil pour réfléchir sur les classes internes, et émettre une nouvelle classe qui accède à tout via la réflexion. MSTest le fait.

Edit : Je veux dire, si vous ne voulez pas inclure -tout- le matériel de test dans votre assemblage original ; cela fonctionne aussi si les membres sont privés.

1 votes

Attends, quoi ? Tu es en train de dire qu'il ne faut pas faire public sealed class ? Quel est votre raisonnement pour cette pierre précieuse ?

0 votes

@crush traumapony ne s'est pas connecté depuis 2009.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X