Search code examples
.netunit-testinginternalsvisibleto

Alternative to InternalsVisibleTo


I am currently trying to write unit tests in my solution, but I want to put my unit tests in a different separate project. The problem is when I am generating some fake testing data I need to set properties of classes, but this is impossible because properties have private/internal set. I found a way to expose internal properties only to some projects with using the attribute InternalsVisibleTo, and this works great, but it looks a little bit messy and unclean. I am looking for more discrete way to expose my private properties to other projects. For example maybe there is a way to expose my properties without explicitly adding an attribute inside of my domain classes? Any idea how I can do this?

EDIT: I found this article about setting InternalsVisibleTo in your csproj file. Has anyone used this? https://bartwullems.blogspot.com/2020/06/internalsvisibleto-in-your-csproj-file.html


Solution

  • There is an alternative described in this blog post with sample code on GitHub, which uses an undocumented attribute to be used in the assembly that accesses the private/internal members.

    Note however the following:

    • This is not documented and not recommended
    • You cannot compile it directly, instead you need to use Roslyn
    • It also appears to ignore access even to private members which is definitely something to be very careful with

    It might however be useful for example when dealing with dynamic assemblies etc, see example below.

    The Code

    Here is what needs to be done, in your code add the IgnoresAccessChecksToAttribute as in the following code (make sure it is NOT under any other namespace or it will not work):

    namespace System.Runtime.CompilerServices
    {
        [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
        public class IgnoresAccessChecksToAttribute : Attribute
        {
            public IgnoresAccessChecksToAttribute(string assemblyName)
            {
                AssemblyName = assemblyName;
            }
    
            public string AssemblyName { get; }
        }
    }
    

    and then anywhere in your code add the attribute as in:

    [assembly: IgnoresAccessChecksTo("AssemblyToAccess")]
    

    or in the csproj file:

    <ItemGroup>
      <AssemblyAttribute Include="System.Runtime.CompilerServices.IgnoresAccessChecksToAttribute">
         <_Parameter1>AssemblyToAccess</_Parameter1>
       </AssemblyAttribute>
    </ItemGroup>
    

    Compilation

    Compilation is tricky as it cannot be compiled with standard means, instead it has to be called via Roslyn, there should be many resources available on how to compile dynamically with Roslyn, but here is the particular details that needs to be done for this compilation to work:

    var compilationOptions = new CSharpCompilationOptions(OutputKind.ConsoleApplication).
                WithMetadataImportOptions(MetadataImportOptions.All);
    
    var topLevelBinderFlagsProperty = typeof(CSharpCompilationOptions)
            .GetProperty("TopLevelBinderFlags", BindingFlags.Instance | BindingFlags.NonPublic);
    
    // 22 is the value of the undocumented member BinderFlags.IgnoreAccessibility
    topLevelBinderFlagsProperty.SetValue(compilationOptions, (uint)1 << 22);
    

    Usage in Assembly Builder

    One legitimate use is when compiling dynamically assemblies that needs access to internal classes, see my answer there for sample code.