Problem with reflection in Unit/Integration tests - c#

I´m dynamically creating an instance of a class with reflection and this works fine, except when trying to do this through unit testing - I´m using the MS testing framework.
I get the familiar error of: "Could not load file or assembly 'Assy' or one of its dependencies. The system cannot find the file specified"
I have copied the dll into the bin\debug bin of the Unit test project - is this not the correct place to put it?
string assyName = "Go.Data.SqlServer";
string typeName = "GoMolaMola.Data.SqlServer.DataProviderFactory";
Assembly assy = Assembly.Load( assyName );
object o = assy.CreateInstance( typeName );
Any ideas? I'm new to unit testing and any help would be appreciated.
Thanks

The bin/Debug folder is not where the unit tests run. Visual Studio will copy the output of your unit test compilation to a TestResults folder (typically keeping the last five test runs, each with a timestamp embedded in the folder name) and run the unit tests there.
If you want the .DLL in that folder, either create a reference to the .DLL from your test project, or use the DeploymentItem attribute to make sure the item is copied to the test directory.

I faced this problem too and none of the above answer worked for me :(
1. Adding reference to project doesn't work for me
2. Adding the DeploymentItem attribute also doesn't work
3. Adding the Post-Build command is also not possible in this case as Unit test engine is creating a new out directory each time with time stamp....and its searching that assembly in this new directory.
but I managed to solve this by enabling deployment and adding the specified file in Local Test Setting -->Deployment

For cases like this, when loading the DLL dynamically is needed from the Unit Testing, I have a post-build event that copies the DLL to that directory. I'd love to know if there's another way to do it. That was the only way that worked for me :(
To edit a Post-Build, right-click over the project, go to Build events, and place the copy, like this, in the Post-Build event command line:
copy $(TargetPath) "$(SolutionDir)yourDir\$(TargetFileName)"

Related

Some Unit Tests are not running in ADO Pipeline (tests from other test projects successfully run). Dotnet test using moq

I have a solution, it has 4 projects, each project has a corresponding test project in a "tests" solution
I've noticed that sometimes a test fails locally but passes the CI build, and depending where the test is located, sometimes it does successfully fail on CI build.
Our ADO pipeline steps looks like:
Here is a csproj from a test project that is running successfully:
Here is a csproj from a test project that isnt running:
Any ideas? I have narrowed down some test classes that I know are running, but I cant tell what is different about those class' csproj versus the ones that are not running.
Turns out the test project that was not running was created outside of other projects:
when i manually move it in finder, and try to replace the reference paths in the csproj to reflect how the paths in the functioning test projects are laid out, the project refuses to load.
anyone know how to easily and safely refactor/move this project??
the best solution here is to create a new project, name it similarly (or name it whatever) then delete the old one once its running properly, and finally rename the new one to the old name

ConfigurationManager.GetSection(sectionName) returns null while performing unit tests

I have a unit tests project with it's own app.config file, which is a mock of a real configuration file defined by target project being tested. This mock file is loaded and processed by unit test code (not by target project), and it works properly if I run only tests within only this one test project.
ConfigurationManager.GetSection(sectionName)
However, if I run tests from several test projects, and other test projects are performed prior to relevant project, the above statement returns null. If discussed test project is performed as first, there is no problem with loading configuration file.
How can I fix loading of configuration file in unit test to work correctly?
Your problem is not ConfigurationManager.GetSection(sectionName) returns null, it is how can I test some code containing ConfigurationManager.GetSection(sectionName)?
And the answer is: wrap it, inject it, then for your test mock it.
You have several examples of pepole facing the same issue:
http://chrisondotnet.com/2011/05/configurationmanager-wrapper-for-unit-testing/
http://weblogs.asp.net/rashid/archive/2009/03/03/unit-testable-configuration-manager.aspx
(The second one is much more detailed, still the idea is the same).
Anyway, this is quite logical that you cannot use information from app.config in a unit test, as an app.config is contextual for the whole application, when it is required to write test absolutely independant. If you use directly an app.config value, then you have non logical coupling.
Facing the same issue this solved it:
app.config should be picked up inside a unit test if it's Copy to Output Directory property set to Copy if newer or if you add the DeploymentItem attribute [DeploymentItem("your.config")].
More detailed description:
http://social.msdn.microsoft.com/Forums/en-US/3e520735-8ced-4092-b681-38b69e0db534/unit-test-configuration#32998bf4-5a76-4083-99da-42f0c3a91559
similar question: MSTest and app.config issue
I think problem is either it could not find the file in test working directory or file itself failed to load.
I have solved this problem by explicitly loading configuration file with name. In your case you can try same.
ExeConfigurationFileMap configMap = new ExeConfigurationFileMap();
configMap.ExeConfigFilename = #"d:\test\test.config";
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);
I used the test project post build command line, but remember to build the project if there are changes:
copy /Y "$(SolutionDir)$(SolutionName)\App.Debug.config" "$(TargetDir)$(ProjectName)$(TargetExt).config"

Dependent DLL is not getting copied to the build output folder in Visual Studio

I have a visual studio solution.
I have many projects in the solution.
There is one main project which acts as the start up and uses other projects.
There is one project say "ProjectX". Its reference is added to main project.
The ProjectX references another .NET dll (say abc.dll) that isn't part of the solution.
Now this abc.dll should be copied to bin/debug folder of main project, but it isn't getting copied there. Why is it not getting copied, any known reasons ?
I found that if ProjectX referenced the abc.dll but didn't directly use any of the types DEFINED in abc.dll, then abc.dll would NOT be copied to the main output folder. (It would be copied to the ProjectX output folder, to make it extra-confusing.)
So, if you're not explicitly using any of the types from abc.dll anywhere in ProjectX, then put a dummy declaration somewhere in one of the files in ProjectX.
AbcDll.AnyClass dummy006; // this will be enough to cause the DLL to be copied
You don't need to do this for every class -- just once will be enough to make the DLL copy and everything work as expected.
Addendum: Note that this may work for debug mode, but NOT for release. See #nvirth's answer for details.
Just a sidenote to Overlord Zurg's answer.
I've added the dummy reference this way, and it worked in Debug mode:
public class DummyClass
{
private static void Dummy()
{
var dummy = typeof(AbcDll.AnyClass);
}
}
But in Release mode, the dependent dll still did not get copied.
This worked however:
public class DummyClass
{
private static void Dummy()
{
Action<Type> noop = _ => {};
var dummy = typeof(AbcDll.AnyClass);
noop(dummy);
}
}
This infomation actually costed me hours to figure out, so I thought I share it.
Yes, you'll need to set Copy Local to true. However, I'm pretty sure you'll also need to reference that assembly from the main project and set Copy Local to true as well - it doesn't just get copied from a dependent assembly.
You can get to the Copy Local property by clicking on the assembly under References and pressing F4.
It looks slick when you make it an assembly attribute
[AttributeUsage(AttributeTargets.Assembly)]
public class ForceAssemblyReference: Attribute
{
public ForceAssemblyReference(Type forcedType)
{
//not sure if these two lines are required since
//the type is passed to constructor as parameter,
//thus effectively being used
Action<Type> noop = _ => { };
noop(forcedType);
}
}
The usage will be:
[assembly: ForceAssemblyReference(typeof(AbcDll.AnyClass))]
Ran into this same issue. Background info: before building, I had added a new Project X to the solution. Project Y depended on Project X and Project A, B, C depended on Project Y.
Build errors were that Project A, B, C, Y, and X dlls could not be found.
Root cause was that newly created Project X targeted .NET 4.5 while the rest of the solution projects targeted .NET 4.5.1. Project X didn't build causing the rest of the Projects to not build either.
Make sure any newly added Projects target the same .NET version as the rest of the solution.
Not sure if this helps but for me, many times I reference a DLL (which automatically adds it to the bin folder of course). However that DLL might need additional DLLs (depending on what functions I'm using). I do NOT want to reference those in my Project because they just simply need to end up in the same folder as the DLL I am actually using.
I accomplish this in Visual Studio by "Adding an existing file". You should be able to add it anywhere except the Add_data folder. personally I just add it to the root.
Then change the properties of that file to ...
Build Action = None (having this set to something like Content actually copies the "root" version to the root, plus a copy in the Bin).
Copy to output folder = Copy if Newer (Basically puts it in the BIN folder only if it is missing, but doesn't do it after that)
When I publish.. my added DLL's only exists in the BIN folder and nowhere else in the Publish location (which is what I want).
You could also check to make sure the DLLs you're looking for aren't included in the GAC. I believe Visual Studio is being smart about not copying those files if it already exists in the GAC on the build machine.
I recently ran in this situation where I'd been testing an SSIS package that needed assemblies to exist in the GAC. I'd since forgotten that and was wondering why those DLLs weren't coming out during a build.
To check what's in the GAC (from a Visual Studio Developer Command Prompt):
gacutil -l
Or output to a file to make it easier to read:
gacutil -l > output.txt
notepad.exe output.txt
To remove an assembly:
gacutil -u MyProjectAssemblyName
I should also note, that once I removed the files from the GAC they were correctly output in the \bin directory after a build (Even for assemblies that were not directly referenced in the root project). This was on Visual Studio 2013 Update 5.
If you right Click the referenced assembly, you will see a property called Copy Local. If Copy Local is set to true, then the assembly should be included in the bin. However, there seams to be a problem with Visual studio, that sometimes it does not include the referenced dll in the bin folder... this is the workaround that worked for me:
In my case, it was the stupidest thing, caused by a default behavior of TFS/VS that I disagree with.
Since adding the dll as a reference to the main project did not work, I decided to add it as an "Existing Item", with Copy Local = Always. Even then the file was not there.
Turns out that, even though the file is present on the VS Solution and everything compiled both locally and on the server, VS/TFS did not add actually add the file to source control. It was not included on the "Pending Changes" at all. I had to manually go to the Source Control Explorer and explicitly click on the "Add items to folder" icon.
Stupid because I've been developing for 15 years in VS. I've run into this before, I just did not remember and somehow I missed it because everything still compiled because of the file being a regular reference, but the file that was added as Existing Item was not being copied because it did not exist on the source control server.
I hope this saves someone some time, since I lost 2 days of my life to this.
Issue:
Encountered with a similar issue for a NuGet package DLL (Newtonsoft.json.dll) where the build output doesn't include the referenced DLL. But the compilation goes thru fine.
Fix:
Go through your projects in a text editor and look for references with "Private" tags in them. Like True or False. “Private” is a synonym for “Copy Local.” Somewhere in the actions, MSBuild is taking to locate dependencies, it’s finding your dependency somewhere else and deciding not to copy it.
So, go through each .csproj/.vbproj file and remove the tags manually. Rebuild, and everything works in both Visual Studio and MSBuild. Once you’ve got that working, you can go back in and update the to where you think they need to be.
Reference:
https://www.paraesthesia.com/archive/2008/02/13/what-to-do-if-copy-local-works-in-vs-but.aspx/
Make sure that the dependent DLL used by you does not have target .NET Framework higher than the target .NET framework of your project's Application.
You can check this by selecting your project, then press ALT+ENTER, then select Application from left side and then select Target Framework of your project.
Suppose,
dependent DLL Target Framework = 4.0 and
Application DLL Target Framework = 3.5 then change this to 4.0
Thank you!
This is a slight tweak on nvirth's example
internal class DummyClass
{
private static void Dummy()
{
Noop(typeof(AbcDll.AnyClass));
}
private static void Noop(Type _) { }
}
I would do add it to Postbuild events to copy necessary libraries to the output directories. Something like XCopy pathtolibraries targetdirectory
You can find them on project properties -> Build Events.
TLDR; Visual Studio 2019 may simply need a restart.
I encountered this situation using projects based on Microsoft.NET.Sdk project.
<Project Sdk="Microsoft.NET.Sdk">
Specifically:
Project1: targets .netstandard2.1
references Microsoft.Extensions.Logging.Console via Nuget
Project2: targets .netstandard2.1
references Project1 via a Project reference
Project2Tests: targets .netcoreapp3.1
references Project2 via a Project reference
At test execution, I received the error messaging indicating that Microsoft.Extensions.Logging.Console could not be found, and it was indeed not in the output directory.
I decided to work around the issue by adding Microsoft.Extensions.Logging.Console to Project2, only to discover that Visual Studio's Nuget Manager did not list Microsoft.Extensions.Logging.Console as installed in Project1, despite it's presence in the Project1.csproj file.
A simple shut down and restart of Visual Studio resolved the problem without the need to add an extra reference. Perhaps this will save someone 45 minutes of lost productivity :-)
You may set both the main project and ProjectX's build output path to the same folder, then you can get all the dlls you need in that folder.
NO NEED FOR DUMMY IN CODE
Just :
add a Reference to the Executeable Project
or/and ensure that the reference in the executeable project has "Copy Local" set to TRUE (which was my "fault") is seems that this "overwrote" the setting in the base referenced library-project...
Other than the common ones above, I had a multi-project solution to publish. Apparently some files target different frameworks.
So my solution: Properties > Specific Version (False)
Add the DLL as an existing item to one of the projects and it should be sorted
VS2019 V16.6.3
For me the problem was somehow the main .proj file ended up with an entry like this for the project whose DLL wasn't getting copied to the parent project bin folder:
<ProjectReference Include="Project B.csproj">
<Project>{blah blah}</Project>
<Name>Project B</Name>
<Private>True</Private>
</ProjectReference>
I manually deleted the line <Private>True</Private> and the DLL was then copied to the main project bin folder on every build of the main project.
If you go to the reference of the problem project in the references folder of the main project, click it and view properties there is a "Copy Local" setting. The private tag equates to this setting, but for me for some reason changing copy local had no effect on the private tag in the .proj file.
Annoyingly I didn't change the copy local value for the reference, no idea how it got set that way and another day wasted tracking down a stupid problem with VS.
Thanks to all the other answers that helped zone me in on the cause.
HTH
I had a similar issue in which a DLL I had included in the project as content and 'Copy always' set, wasn't being copied to the bin folder. I solved this by adding a dependentAssembly reference to the DLL in the app.config.

app.configs and MSTest Project - null reference for a connection string

When I try to run Unit Tests (mstest) I run into this issue.
The line of code:
_mainCnStr = System.Configuration.ConfigurationManager.
ConnectionStrings["main"].ConnectionString;
Comes back as a null reference
It doesn't do this in the main UI project when I run it. What is the right method to get this connection string setting seen by the Unit Test project? I tried embedded as a resource. I tried Copy Always. What is the right combination of settings that will fix this for me?
One thing to watch with MSTest (from the IDE at least); it doesn't run the tests in the regular output (bin) folder, and it doesn't respect the project's file inclusions ("Copy to Output Directory"). You often need to explicitly tell it (MSTest) which files to put into the test area. You will need to include the "app.config" in this list; either via the testrunconfig ("Deployment"), or by adding an attribute ([DeploymentItem]) to the affected test fixtures.
You should add an app.config to the unit test project. It won't automatically use the settings in UI application's app.config.
I'm assuming mstests are, like nunit tests, embedded in a seperate assembly which gets loaded by the testing application? In that case, you may need to create some test set-up code which loads in the configuration file.

Changing Output path of the Unit Test project in Visual Studio 2008

I changed the output path of the test project, because the default path doesn't conform to our projects directory structure. After I did that, Visual Studio 2008 fails to run the tests, because it can't find the Unit Test project assembly.
What else do I have to change for the Unit Test Engine to find the assembly?
There are at least three ways to solve this problem
Set up the output path before you run any test in the solution (as suggested by Paulius Maruška).
Close the solution, delete the directory TestResults (under your solution folder) and then open the solution and run all tests (Test -> Run -> All...)
Add your assembly to the list of files to deploy in the .testconfig file (suggested by Ty)
Solution number 3 is probably not recommended, since solution 1 or 2 will achieve the same
without adding a second reference to the output path.
Please note that solution number 2 will delete any test history you may have.
If you open up your .testrunconfig file and go to the Deployment option, you can add your test assembly to the list of files to deploy. You should then be able to run your tests.
I figured this out, I think.
This is the only solution I have found. Adding the assembly to the files to deploy list (as suggested by Ty) works, but it kind of feels dirty, so I didn't want to do that.
Visual Studio accepts the changed path, only when you change it before running any of the tests. So, the solution to my own question is: You have to create a new test project, change it's build path, add all of the tests from the old test project.
Close your project, then delete your hidden .suo file and the csproj.user file. Then re-open the project. That fixes it.

Categories

Resources