diff --git a/docs/help/_posts/2015-01-01-how-nsub-works.markdown b/docs/help/_posts/2015-01-01-how-nsub-works.markdown index 3cd6a1ec..510572e2 100644 --- a/docs/help/_posts/2015-01-01-how-nsub-works.markdown +++ b/docs/help/_posts/2015-01-01-how-nsub-works.markdown @@ -46,14 +46,34 @@ If `DoStuffWith(string s)` is not `virtual`, the `SubstituteForOriginal` class w This can cause all sorts of problems if we accidentally attempt to configure a non-virtual call, because NSubstitute will get confused about which call you're talking about. Usually this will result in a run-time error, but in the worst case it can affect the outcome of your test, or even the following test in the suite, in non-obvious ways. Thankfully we have [NSubstitute.Analyzers](/help/nsubstitute-analysers) to detect these cases at compile time. -### Internal members +### Internal members and types -Similar limitations apply to `internal virtual` members. Because `SubstituteForOriginal` gets generated in a separate assembly, `internal` members are invisible to NSubstitute by default. There are two ways to solve this: +Similar limitations apply to `internal` members and types. Because `SubstituteForOriginal` gets generated in a separate assembly, they are invisible to NSubstitute and your test-assembly by default. There are two ways to solve this: -* Use `[assembly: InternalsVisibleTo(InternalsVisible.ToDynamicProxyGenAssembly2)]` in the test assembly so that the `internal` member can be overridden. -* Make the member [`protected internal virtual`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/protected-internal) so that sub-classes can access the member. +The first possibility is to change the visibility of the member or type that shall be substituted. If you change the visibility of members to [`protected internal`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/protected-internal), they get _visible_ for types that derive from it. The visibility of `internal` types must be set to [`public`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/public). However, keep in mind that changing visibilities should be well considered. The next alternative has less side effects on the maintainability of your project. -Remember that if the member is non-virtual, NSubstitute will not be able to intercept it regardless of whether it is `internal` or `InternalsVisibleTo` has been added. +The second possibility is to make the `internal` members and types visible to your test-assembly and to the library that NSubstitute uses under the hood. For this you need to _allow_ specific assemblies to accesss the `internal`s. You can do this by either adding an attribute to the assembly that contains the `internal`s or add an annotation to your project file. + +#### Option 1. Use an assembly attribute +Add the following code to an arbitrary `.cs`-file of the project that contains the `internal` types. +``` +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("DynamicProxyGenAssembly2")] +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("name of the assembly that contains your tests")] +``` + +#### Option 2. Use a tag in the project file (works with .NET 5 and above) +Add an `ItemGroup` that contains the `InternalsVisibleTo`-element beneath the `Project`-element in your `.csproj`-file. +```xml + + ... + + + + + +``` + +Remember that if members are non-virtual, NSubstitute will not be able to intercept it regardless of whether it is `internal` or `InternalsVisibleTo` has been added. The good news is that [NSubstitute.Analyzers](/help/nsubstitute-analysers) will also detect attempts to use `internal` members at compile time, and will suggest fixes for these cases.