Having issues unit testing internal class in c# [duplicate] - c#

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?

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.

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

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

starting from .Net 5, you can use also this syntax in the csproj of the project being tested:
<ItemGroup>
<InternalsVisibleTo Include="MyProject.Tests" />
</ItemGroup>

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>

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.

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.

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/";
......
......
......
}
}

In .NET Core 2.2, add this line to your Program.cs:
using ...
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("MyAssembly.Unit.Tests")]
namespace
{
...

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")]

Related

global usings and .NET Standard 2.0

I recently recognized that I can use the C# 10 feature file-scoped namespaces in .NET Standard 2.0 projects as well by setting <LangVersion>10</LangVersion> in the csproj file.
However, global usings don't work that way, I'm getting compiler errors due to missing using statements.
Are there any tweaks so that I can use global usings in a .NET Standard 2.0 library as well?
I'm not sure why it doesn't work with a separated .cs file. However, a workaround that works is using the MSBuild syntax. In your .csproj you can add the following:
<ItemGroup>
<Using Include="System.Linq" />
</ItemGroup>
There are some keywords you can use - like Alias or Static -, as you would do in a normal .cs file.
<ItemGroup>
<Using Include="Test.Namespace" Alias="Domain" />
</ItemGroup>
And then in your code, you can do the following:
namespace Test.Namespace
{
public class TestClass {}
}
namespace Another.Namespace
{
new Domain.TestClass();
}
If it helps, I found this information in the following blog post.

Call a managed C# library with P/invoke without Assembly.Load or similar

I've been around for days looking for this but all I find is how to call unmanaged libraries from C# using P/Invoke. I need to do it differently: I'm looking to use P/Invoke to call a managed assembly from another one (or use something else, avoiding to call Assembly.Load, Assembly.LoadFrom, etc.) basically due to a CoreRT/NativeAOT limitation (see here).
Basically, the idea of using CoreRT/NativeAOT is due to the native executable generation, which would improve a bit my app's security as common decompilers won't work with it (except IDA and a clever dev with ASM knowledge, but they're harder to come by). Considering that CoreRT/NativeAOT cannot (it can, but the .NET team just doesn't want to right now...) load external assemblies using any of the .NET Interop methods (Assembly.Load, Assembly.LoadFrom, etc.) but it can use DllImport, I'd like to call an external assembly that I don't really care much if it's decompiled or not without using any of those Assembly loading methods.
Yeah, I know I could write a wrapper or something with CoreRT itself to generate a native lib and call it with P/Invoke from the app, but in the case of Entity Framework which doesn't compile due to Reflection.Emit, it's not a possibility.
The ideal solution here would be to know how to call any .NET assembly (DLL) from another C# app/assembly WITHOUT using Assembly.Load/LoadFrom/LoadFromStream/etc. using other methods, be either P/Invoke (can it?) or other ones.
SOLUTION
Thanks to #ChristianHeld for his suggestion to use .NET 5.0's Native Exports (plus also thanks to Aaron Robinson for his code. I got it working this way:
.csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
ADD THIS -> <EnableDynamicLoading>true</EnableDynamicLoading>
ADD THIS -> <DnneAddGeneratedBinaryToProject>true</DnneAddGeneratedBinaryToProject>
</PropertyGroup>
<ItemGroup>
ADD THIS -> <PackageReference Include="DNNE" Version="1.*" />
</ItemGroup>
</Project>
Library .NET Code (stripped):
[UnmanagedCallersOnlyAttribute]
public static void Init()
{
// ... Some code here...
}
Caller .NET Code (sample):
class Program
{
const string LIBNAME = #"LibraryNE.dll";
[DllImport(LIBNAME)] public static extern void Init();
static void Main(string[] args)
{
Init();
}
}
IMPORTANT: When running with VSCode (F5) it may say something like this:
Failed to initialize context for config: C:\Project\Library.runtimeconfig.json. Error code: 0x80008092
Disregard this, as it seems to happen because VSCode debugs the app with dotnet.exe, disregarding each assembly's runtimeconfig.json (somehow it throws LibHostInvalidArgs. No idea why).
If you execute your app's .EXE directly, it will work (just used it with a CoreRT/NativeAOT-generated binary). The solution to this is to edit your launch.json file and change .dll with .exe in configurations -> program.
Also, remember to copy the .NET dll as well. It seems that when you publish, only the native library (suffixed with NE) is copied, but it won't work by itself as it's just a wrapper. It needs the real .NET dll to be in the same folder as well.
The debugging experience isn't so great, as when you debug the method it seems to use a different, non-existing source file so the line numbers when you step through don't match. It's debuggable, but you'll be doing so against ghost/offset lines.

Avoiding or fixing namespace pollution in .Net Core

Summary
For my CS capstone project we are encountering an issue with a class name existing in two different dependencies. Specifically, we are using a dependency for using MySQL with Entity Frame and one for just connected and executing MySQL queries directly.
Background
The non-EF is owned by a component outside of the project, and this database is one of our main ways of interacting with the database. It has been requested by the client/mentor that any additions or changes we need be made to a separate database, which is the database EF is connecting to.
The question
My question is essentially about how do I fix error the type <class-name> exists in both..., but I'm more wondering about the root problem of namespace pollution in .Net Core and the courses of action we can take. I have looked into the error and the initial results described a fix that is only applicable in .Net not .Net Core and an explanation that .Net Core does not support aliasing.
Potential fixes
Separate projects - I have asked someone I know who has more experience with .Net, and he suggest making separate projects. While that would obviously work in terms of getting rid of a build error, I do not know how we could make use of one in the main ASP.Net app. I am assuming either both need to be apps or making one into a library. I am also assuming that if it is a separate library it will have the same problem we are having now.
Removing one dependency - I am currently considering that the less than ideal solution is rewriting the code that relies on EF to use the direct MySQL connection dependency. There is less code relying on that EF database, so it would be simpler to rewrite that and some SQL.
Aliasing or full reference - The results I have found that seem to only be applicable to .Net describe using an alias or referencing the full path of the decency in the type. From what I have read, this is not currently supported in .Net Core. If it is, how may I go about it?
using System;
using System.Collections.Generic;
using MySql.Data.MySqlClient;
namespace OVD.API.GuacamoleDatabaseConnectors
{
public class GuacamoleDatabaseConnector : IDisposable
{
private MySqlConnection connection;
...
The error is on the MySqlConnection type and is, in full: GuacamoleDatabaseConnectors/GuacamoleDatabaseConnector.cs(81,16): error CS0433: The type 'MySqlConnection' exists in both 'MySql.Data, Version=8.0.15.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d' and 'MySqlConnector, Version=0.49.2.0, Culture=neutral, PublicKeyToken=d33d3e53aa5f8c92' [/Users/markbeussink/Action/OVD/OVD.API/OVD.API.csproj]
Here is the .cs.proj
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App"/>
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All"/>
<PackageReference Include="Ldap.NETStandard" Version="1.0.3"/>
<PackageReference Include="MySql.Data" Version="8.0.15"/>
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.2.0"/>
</ItemGroup>
</Project>
Just create a new project "class library" and inside this project, you can create an interface which gives you access to a method from one of your component (you need to implement your "component" and its method inside this project). Something like in facade pattern. Then in the rest of your solution, you will use a newly created project reference only. This solution allows you define your own namespace name
It's really bad form for two separate projects to have a type with the same namespace and the same name, for the reason you've just discovered. It is not at all normal or expected that you would run into such a conflict, and you may well never encounter it again in your career.
It looks like this project:
https://www.nuget.org/packages/MySqlConnector/
decided to clobber the namespace of the more official ADO.NET provider for MySQL:
https://www.nuget.org/packages/MySql.Data
by defining a type called: MySql.Data.MySqlClient.MySqlConnection, instead of using MySqlConnector.MySqlClient.MySqlConnection, or somesuch.
The best way forward is to exclude one of these from your projects, and use just the other. Here the obvious choice would be to switch from
https://www.nuget.org/packages/Pomelo.EntityFrameworkCore.MySql/
to
https://www.nuget.org/packages/MySql.Data.EntityFrameworkCore/
But I don't have any opinion on the relative merits of these libraries.
If you can't do this, C# provides a compiler directive for you to alias one of the assemblies with a different namespace. See https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs0433
This will in effect add a new outermost namespace level to the offending assembly, so the other MySqlConnection would be known (only in your code) as SomeAlias.MySql.Data.MySqlClient.MySqlConnection.

Microsoft Fakes Framework - I can't use internal class

I'v a problem with Fakes Framework and internal class.
I've just readed and used the advice here: How to mock/isolate internal classes in VS 2012 with Fakes Framework shims?
but, I still not see internal classes.
I've this solution:
ACQTool (class library project)
ACQTool.UnitTests (test project)
in ACQTool namespace there is ACQTool.Utils internal class.
in ACQTool/AssemblyInfo.cs I've added these lines:
[assembly: InternalsVisibleTo("ACQTool.UnitTests, PublicKey=57ad8399-13fd-4d4d-90fd-c521c2164d25")]
[assembly: InternalsVisibleTo("ACQTool.Fakes, PublicKey=0024..47bc")]
[assembly: InternalsVisibleTo("Microsoft.QualityTools.Testing.Fakes, PublicKey=0024..47bc")]
After build, I can use ACQTool.Utils in test class, but not exist ACQTool.Fakes.ShimUtils/StubUtils.
Help me please.
It's kinda weird I just replicated your problem and surely it wasn't generating the internals in Fake assembly at first. I followed below steps and it started working even for other namespaces too:
Add a public class under the namespace Utils.
Rebuild the Test project and the internal will start showing up.
Remove that public class and rebuild again.
I removed everything from Utils namespace and added new internal class and it is working fine since then.
It's just a workaround to generate namespace that contains internals.
Probably You should paste Public key generated by sn.exe tool.
Usually it stored somewhere like:
"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\sn.exe"
call it from command line:
sn.exe -p SomeName.snk SomeName.PublicKey
sn.exe -tp SomeName.PublicKey
and paste the output to the "InternalsVisibleTo" Public key param.
Important note from that msdn page that I missed: The Fakes framework uses the same key to sign all generated assemblies, so the public key if signing should ALWAYS be
PublicKey=0024000004800000940000000602000000240000525341310004000001000100e92de‌​cb949446f688ab9f6973436c535bf50acd1fd580495aae3f875aa4e4f663ca77908c63b7f0996977c‌​b98fcfdb35e05aa2c842002703cad835473caac5ef14107e3a7fae01120a96558785f48319f66daab‌​c862872b2c53f5ac11fa335c0165e202b4c011334c7bc8f4c4e570cf255190f4e3e2cbc9137ca57cb‌​687947bc

Unable to use methods of one solution in another even after adding references

I have two different VS projects:
1) Utilities
2) Modules
In the Utilities project, I have a Library.cs
In Library.cs, I have a method Login().
I have defined Library.cs as a public static class
I have also defined Login as a public static method
In the Modules project, I have a test class Test1.cs
I have added using Utilities in this class.
I have also added reference to the Utilities.dll (Add reference --> browse to bin folder --> Release)
Now, when I try:
Library.Login();
it says there is no definition for Login() in Library.cs
I have tried cleaning the solution, and rebuilding it as well. Am I doing something wrong or missing something?
Just guess..
Look on you project's .NET Framework versions. It seems that they compiled against different versions of framework.
Most often this is a case of that kind of behavior.
Hope this helps.

Categories

Resources