645

I'm trying to figure out if I should start using more of internal access modifier.

I know that if we use internal and set the assembly variable InternalsVisibleTo, we can test functions that we don't want to declare public from the testing project.

This makes me think that I should just always use internal because at least each project (should?) have its own testing project.

Why shouldn't one do this? When should one use private?

starball
  • 20,030
  • 7
  • 43
  • 238
Hertanto Lie
  • 8,832
  • 7
  • 28
  • 27
  • 1
    Worth mentioning - you can often avoid the need for unit testing your internal methods by using `System.Diagnostics.Debug.Assert()` within the methods themselves. – Mike Marynowski Mar 30 '17 at 02:32

10 Answers10

1468

Internal classes need to be tested and there is an assembly attribute:

using System.Runtime.CompilerServices;

[assembly:InternalsVisibleTo("MyTests")]

Add this to the project info file, e.g. Properties\AssemblyInfo.cs, for the project under test. In this case "MyTests" is the test project.

General Grievance
  • 4,555
  • 31
  • 31
  • 45
EricSchaefer
  • 25,272
  • 21
  • 67
  • 103
  • 93
    This should really be the accepted answer. I don't know about you guys, but when the tests are "too far" from the code they're testing I tend to get nervous. I'm all for avoiding to test anything marked as `private`, but too many `private` things might very well point to an `internal` class that is struggling to be extracted. TDD or no TDD, I prefer having more tests that test a lot of code, than to have few test that exercise the same amount of code. And avoiding to test `internal` stuff doesn't exactly help to achieve a good ratio. – s.m. May 28 '12 at 07:50
  • 2
    I wrapped this attribute with and #if RELEASE directive so the internals would not be visible to anything in a release build. Just a thought. – CAD bloke Nov 06 '13 at 22:27
  • 1
    @s.m. Totally agree...Plus, it's pretty much -impossible- to test UI code, so I generally defer a lot of my 'custom' UI layout logic into methods that I can test without necessarily running a WPF or WinForms application and seeing the result (i.e. ordering of elements, checking positional information, etc...etc...) This logic is definitely marked as internal and absolutely *cannot* be tested through 'public' means...I can't stand it when people relate 'public' to 'testable', they are *not* one and the same for every single case...and I'm an advocate for TDD... – Robert Petz Dec 04 '13 at 18:02
  • 8
    There's a great [discussion](http://lostechies.com/derickbailey/2014/01/03/semantics-modules-and-testing-why-and-how-i-test-internal-components-not-private-methods/) going on between @DerickBailey and Dan Tao regarding the semantic difference between **internal** and **private** and the need to test _internal_ components. Well worth the read. – Kris McGinnes Jan 21 '14 at 05:22
  • 45
    Wrapping in and `#if DEBUG`, `#endif` block will enable this option only in debug builds. – The Real Edward Cullen Feb 04 '14 at 16:33
  • @CADbloke Does that mean you don't run your unit tests against a release build? We run unit tests both for debug and release builds. Devs run the debug built unit tests locally, build server runs them for release builds. Makes sure we catch differences between debug and release code caused by different compilation settings for both (optimization for example). – Marjan Venema Mar 08 '15 at 10:17
  • @Marjan That's a good point and yes I changed the way I do that, I test the release builds, then comment out the InternalsVisibleTo code for a deployment build. If you commit the code and tag it at that point you keep your milestone for that deployment, then revert the commented code and carry on. Theoretically there could be side-effects to this but it's better than not testing Release code and shipping code with a potential security hole. – CAD bloke Mar 08 '15 at 10:37
  • 1
    @CADbloke Cool. Is `InternalsVisibleTo` a security hole because any assembly with the specified name would get access to the internals? I figure that .Net is inherently so insecure - because of reflection and all the (IL) disassemblers out there - that I wouldn't expend the effort of removing it for a release build... Am I missing something here? – Marjan Venema Mar 08 '15 at 10:41
  • 4
    @Marjan Yes, unless you Strong-Name sign the Assemblies and include the key in the InternalsVisibleTo attribute. See http://adelkhalil.bloggingabout.net/2007/10/12/tiny-tip-improve-security-with-internalsvisibleto-attribute/ It depends on your level of paranoia, I guess. – CAD bloke Mar 08 '15 at 10:53
  • 25
    This is the correct answer. Any answer that says that only public methods should be unit tested is missing the point of unit tests and making an excuse. Functional testing is black box oriented. Unit tests are white box oriented. They should testing "units" of functionality, not just public APIs. – Gunnar Aug 18 '15 at 23:00
  • 13
    For .NET Core - add it to any .cs file in the app. See details here - https://stackoverflow.com/a/42235577/968003 – Alex Klaus Nov 02 '17 at 01:13
  • 2
    Alex Klaus add that as an answer. I just spent a while digging for that. .NET Core is new enough the question needs a new answer. – Sentinel Jan 15 '18 at 23:11
  • Great solution for internal classes! But in VS2017 I still get the error message that VS cannot create a unit test for such classes. I have to create one manually. – Markus L Feb 09 '18 at 09:42
  • This is a bad answer, from my point of view. Internal should be stay such, not have a flag that allow them to be internal depending on the caller. – motoDrizzt May 24 '18 at 09:11
  • The opinion of so many to not test internals and privates explains why there is so much buggy software. To being lazy and test your code. – Matthew Whited Jun 18 '23 at 15:52
179

Adding to Eric's answer, you can also configure this in the csproj file:

<ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
      <_Parameter1>MyTests</_Parameter1>
    </AssemblyAttribute>
</ItemGroup>

Or if you have one test project per project to be tested, you could do something like this in your Directory.Build.props file:

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

See: https://stackoverflow.com/a/49978185/1678053
Example: https://github.com/gldraphael/evlog/blob/master/Directory.Build.props#L5-L12

galdin
  • 12,411
  • 7
  • 56
  • 71
  • 15
    This should be the top answer imo. All the other answers are very outdated as .net is moving away from assembly info and moving the functionality into csproj definitions. – mBrice1024 May 17 '20 at 15:54
  • This approach won't work in a Unity project, as the csproj files are rebuilt by Unity. In this case the accepted answer is the way to go. – piersb Jan 10 '22 at 11:43
  • 2
    Very good answer tbh! It's way cleaner than having to add this `AssemblyInfo` file. – Rickless Feb 06 '22 at 12:50
  • 2
    Nice, but already outdated. Use `` instead, as described in [ihebiheb's answer](https://stackoverflow.com/a/73261024/419761). – l33t Feb 23 '23 at 13:34
  • This did not work for me with `.NET Framework 4.8`. But the @EricSchaefer answer using `AssemblyInfo.cs` did work. – JohnB Jun 22 '23 at 17:32
137

If you want to test private methods, have a look at PrivateObject and PrivateType in the Microsoft.VisualStudio.TestTools.UnitTesting namespace. They offer easy to use wrappers around the necessary reflection code.

Docs: PrivateType, PrivateObject

For VS2017 & 2019, you can find these by downloading the MSTest.TestFramework nuget

Johnny Wu
  • 1,297
  • 15
  • 31
Brian Rasmussen
  • 114,645
  • 34
  • 221
  • 317
57

Starting with .NET 5, you can use also this syntax in the csproj file of the project being tested:

  <ItemGroup>
    <InternalsVisibleTo Include="MyProject.Tests" />
  </ItemGroup>
mfluehr
  • 2,832
  • 2
  • 23
  • 31
ihebiheb
  • 3,673
  • 3
  • 46
  • 55
20

I'm using .NET Core 3.1.101 and the .csproj additions that worked for me were:

<PropertyGroup>
  <!-- Explicitly generate Assembly Info -->
  <GenerateAssemblyInfo>true</GenerateAssemblyInfo>
</PropertyGroup>

<ItemGroup>
  <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
  <_Parameter1>MyProject.Tests</_Parameter1>
  </AssemblyAttribute>
</ItemGroup>
Community
  • 1
  • 1
Floating Sunfish
  • 4,920
  • 5
  • 29
  • 48
  • 2
    The addition of explicitly generating assembly info was what finally made it work for me as well. Thank you for posting this! – thevioletsaber Mar 11 '20 at 16:16
11

Keep using private by default. If a member shouldn't be exposed beyond that type, it shouldn't be exposed beyond that type, even to within the same project. This keeps things safer and tidier - when you're using the object, it's clearer which methods you're meant to be able to use.

Having said that, I think it's reasonable to make naturally-private methods internal for test purposes sometimes. I prefer that to using reflection, which is refactoring-unfriendly.

One thing to consider might be a "ForTest" suffix:

internal void DoThisForTest(string name)
{
    DoThis(name);
}

private void DoThis(string name)
{
    // Real implementation
}

Then when you're using the class within the same project, it's obvious (now and in the future) that you shouldn't really be using this method - it's only there for test purposes. This is a bit hacky, and not something I do myself, but it's at least worth consideration.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 2
    If the method is internal does this not preclude its use from the testing assembly? – Ralph Shillington Feb 22 '10 at 15:47
  • @Ralph: Not using InternalsVisibleTo. – Jon Skeet Feb 22 '10 at 16:35
  • 7
    I occasionally use the `ForTest` approach but I always find it dead ugly (adding code which provides no actual value in terms of production business logic). Usually I find I had to use the approach because the design is somwhat unfortunate (i.e. having to reset singleton instances between tests) – ChrisWue Apr 03 '12 at 18:53
  • 2
    Tempted to downvote this - what is the difference between this hack and simply making the class internal instead of private? Well, at least with compilation conditionals. Then it gets really messy. – CAD bloke Nov 06 '13 at 10:18
  • 8
    @CADbloke: Do you mean making the *method* internal rather than private? The difference is that it's obvious that you really *want* it to be private. Any code within your production codebase which calls a method with `ForTest` is *obviously* wrong, whereas if you just make the method internal it looks like it's fine to use. – Jon Skeet Nov 06 '13 at 10:28
  • 1
    Thanks, I get that but I was concerned the method itself is now accessible from a wider scope. Granted that scope is "internal" so it is still safe from the prying eyes of an unsuspecting public, so no downvote (my assumption was off the mark a bit there). I saw an answer elsewhere that recommended using partial classes if one was making a habit of this method. Thanks again for taking the time to answer. :) – CAD bloke Nov 06 '13 at 10:34
  • 1
    @CADbloke: Partial classes wouldn't make any difference here either. What would be nice would be an attribute which a static analysis tool could use to check that it wasn't being used from non-test assemblies. – Jon Skeet Nov 06 '13 at 10:36
  • 1
    The only reason to use partial classes in this case would be to hide the clutter and exclude it from a release build. – CAD bloke Nov 06 '13 at 10:42
  • 2
    @CADbloke: You can exclude individual methods within a release build just as easily in the same file as using partial classes, IMO. And if you *do* do that, it suggests that you're not running your tests against your release build, which sounds like a bad idea to me. – Jon Skeet Nov 06 '13 at 10:54
10

You can use private as well and you can call private methods with reflection. If you're using Visual Studio Team Suite it has some nice functionality that will generate a proxy to call your private methods for you. Here's a code project article that demonstrates how you can do the work yourself to unit test private and protected methods:

http://www.codeproject.com/KB/cs/testnonpublicmembers.aspx

In terms of which access modifier you should use, my general rule of thumb is start with private and escalate as needed. That way you will expose as little of the internal details of your class as are truly needed and it helps keep the implementation details hidden, as they should be.

Steven Behnke
  • 3,336
  • 3
  • 26
  • 34
4

For .NET core you can add the attribute to the namespace as [assembly: InternalsVisibleTo("MyUnitTestsAssemblyName")]. e.g. Something like

using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Applications.ExampleApp.Tests")]
namespace Applications.ExampleApp
 internal sealed class ASampleClass : IDisposable
    {
        private const string ApiVersionPath = @"api/v1/";
        ......
        ......
        ......
        }
    }
Amit Sood
  • 385
  • 3
  • 7
2

In .NET Core 2.2, add this line to your Program.cs:

using ...
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("MyAssembly.Unit.Tests")]

namespace
{
...
Pang
  • 9,564
  • 146
  • 81
  • 122
balintn
  • 988
  • 1
  • 9
  • 19
0

Add InternalsVisibleTo.cs file to project's root folder where .csproj file present.

Content of InternalsVisibleTo.cs should be following

using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("AssemblyName.WhichNeedAccess.Example.UnitTests")]
Black_Rider
  • 1,465
  • 2
  • 16
  • 18