I'm trying to work out how to (and at the same time best practice) use an app.config file in unit tests (MSTest specifically).
So I have the actual project then a separate project. the actual project has an app.config - and it seems that the unit tests are using that file and not ones I am trying to specify.
I have tried the following:
Putting a copy of app.config in the root of the test project, removing some key config sections that are used within the code so thus should cause exceptions and failures - this doesn't seem to work
using
[DeploymentItem("app.config")]
Which I believe picks up the app.config from the test project root and deploys that?? Strangely, I also tried to change the path to
[DeploymentItem("Data\\app.config")]
Which is a directory I use to load other deployment items - however it complains that it cannot find the app.config.
What am I doing wrong here - and also am I doing it the right way (assuming I am missing something simple). I basically want a separate app.config where I can use specific test settings rather than use the real app.config copied or referenced.
Related
What I'm using
I'm using:
.NET 6 with <Nullable>disable</Nullable>,
NUnit (3.13.3),
and System.Configuration.ConfigurationManager.
What I have
Currently, I have a simple solution consisting of 3 projects:
A class library,
a console app,
and a unit test project
The class library has a single class Foo which uses ConfigurationManager to read setting from configuration file
using System.Configuration;
namespace ClassLibrary;
public class Foo
{
public static string Bar = ConfigurationManager.AppSettings["setting"];
}
App.Config is located in the solution root, it's linked to each project and looks like this
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="setting" value="Kitty meow" />
</appSettings>
</configuration>
When I use the Foo class in console app the setting value is read from the file just fine
using ClassLibrary;
Console.WriteLine(Foo.Bar); // Bar property contains the correct value
Console.ReadKey();
However, when I try to use the Foo class in unit test, the value of Bar property is null
using ClassLibrary;
using NUnit.Framework;
namespace TestProject;
public class ConfigurationManagerTest
{
[Test]
public void MakeSureThatConfigurationManagerReadsFromFileCorrectly()
{
Assert.That(Foo.Bar, Is.Not.Null); // Bar property is null
}
}
The full source is available on GitHub:
https://github.com/dva-meow/UnitTestConfiguration
What I have tried
I've been trying to figure out what was causing this but had no success. Here's a list of what I've tried:
1. Copying the configuration file — In this SO post as well as in this one a few people mention that it's necessary to link/copy the App.Config file to the unit test project. This is working for the console app but not for the unit test (I've tried both linking and copying the file).
2. Making sure the configuration file is present in the executing directory — This SO answer says that:
When you compile an application, its app.config is copied to the bin directory with a name that matches your exe. For example, if your exe was named "test.exe", there should be a "text.exe.config" in your bin directory.
I made sure this was indeed the case for my project and I can confirm, that the renamed App.Config file is being copied to the bin directory of each project.
3. Investigating when initialization of static field occur — This SO answer suggests that:
Static classes are initialized prior to first use of any static member of that class. Unit Test code is no exception to this rule.
I was experimenting in debug for a while but haven't discovered anything useful. The correct value is present in the console app while in unit test it's always null, regardless of how many times I try to access the Bar property. (Also, I find this a bit odd as I don't believe it matters at all whether I assert the property for null right away or assign it to a variable before doing it.)
4. Experimenting with case-sensitivity — I tried renaming the configuration file to rule out the possibility that the ConfigurationManager is case-sensitive when used in unit tests.
What I need
I could probably come up with some sort of a workaround to avoid this issue but I would very much like to get to the bottom of this. All circumstances seem to be the same for both the console app as well as the unit test project and I'm really confused why it's not working the same in both cases.
What am I doing wrong?
Simple. You have an App.config but you aren't running your app. You are running NUnit. Each NUnit test assembly may have a config file of its own and you have to follow NUnit conventions rather than .NET conventions to make sure the config is used.
In this case, rename your config based on your test assembly name: e.g. my.test.assembly.dll.config and make sure it's in the same directory as the assembly.
See this (ancient but still basically correct) blog post for a more detailed explanation: http://charliepoole.org/technical/how-nunit-finds-config-files.html
I am helping a team whose builds have started failing due to test failures.
The failures are being caused by missing connection string configuration. I checked the usual issues in respect of the config file to ensure that the connection string was specified with exactly the right name.
In the end I obtained the full path of the config file to check that the one on the build server contained the exact configuration that was expected.
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
The path did not point to the TestProject.exe.config file, but instead pointed to the vstest.executionengine.x86.exe.Config at the following location:
C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.executionengine.x86.exe.Config
This file contains no connection strings at all.
When I write out all of the available connection strings from configuration, I get the default connection string:
Name: LocalSqlServer Connection: data source=.\SQLEXPRESS;Integrated
Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User
Instance=true . Aborting test execution.
This is coming from the machine.config file (kudos petelids).
So the big question is:
Why is the vstest.executionengine.x86.exe.Config being used rather than the app.config (at runtime TestProject.exe.config)? (I can guess that this is because the process running is the test runner, but I think it is fair to say that you would expect the test runner to let the test project use its own config file, which is what normally happens).
I think it is fair to say that you would expect the test runner to let the test project use its own config file, which is what normally happens
That's perfectly true assumption when working with NUnit, xUnit, etc. but not with Microsoft Test Runners (MSTest and VSTest). They simply ignore target assembly config file and use their own config.
There are two solution to this problem:
Change MSTest to NUnit or xUnit
Use custom config file (not the default one)
MSTest runs tests in isolated mode by default.
The solution to this issue was to add a new test project and move the tests into it.
The new project behaved like all of the other projects, running the tests in an isolated process and using the app.config file from the test project.
I'm putting this down to a quirk.
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"
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.
I am unit testing a .NET application (.exe) that uses an app.config file to load configuration properties. The unit test application itself does not have an app.config file.
When I try to unit test a method that utilizes any of the configuration properties, they return null. I'm assuming this is because the unit test application is not going to load in the target application's app.config.
Is there a way to override this or do I have to write a script to copy the contents of the target app.config to a local app.config?
This post kind-of asks this question but the author is really looking at it from a different angle than I am.
EDIT: I should mention that I'm using VS08 Team System for my unit tests.
In Visual Studio 2008 I added the app.config file to the test project as an existing item and selected copy as link in order to make sure it's not duplicated. That way I only have one copy in my solution. With several test projects it comes in really handy!
The simplest way to do this is to add the .config file in the deployment section on your unit test.
To do so, open the .testrunconfig file from your Solution Items. In the Deployment section, add the output .config files from your project's build directory (presumably bin\Debug).
Anything listed in the deployment section will be copied into the test project's working folder before the tests are run, so your config-dependent code will run fine.
Edit: I forgot to add, this will not work in all situations, so you may need to include a startup script that renames the output .config to match the unit test's name.
Whether you're using Team System Test or NUnit, the best practice is to create a separate Class Library for your tests. Simply adding an App.config to your Test project will automatically get copied to your bin folder when you compile.
If your code is reliant on specific configuration tests, the very first test I would write validates that the configuration file is available (so that I know I'm not insane)
:
<configuration>
<appSettings>
<add key="TestValue" value="true" />
</appSettings>
</configuration>
And the test:
[TestFixture]
public class GeneralFixture
{
[Test]
public void VerifyAppDomainHasConfigurationSettings()
{
string value = ConfigurationManager.AppSettings["TestValue"];
Assert.IsFalse(String.IsNullOrEmpty(value), "No App.Config found.");
}
}
Ideally, you should be writing code such that your configuration objects are passed into your classes. This not only separates you from the configuration file issue, but it also allows you to write tests for different configuration scenarios.
public class MyObject
{
public void Configure(MyConfigurationObject config)
{
_enabled = config.Enabled;
}
public string Foo()
{
if (_enabled)
{
return "foo!";
}
return String.Empty;
}
private bool _enabled;
}
[TestFixture]
public class MyObjectTestFixture
{
[Test]
public void CanInitializeWithProperConfig()
{
MyConfigurationObject config = new MyConfigurationObject();
config.Enabled = true;
MyObject myObj = new MyObject();
myObj.Configure(config);
Assert.AreEqual("foo!", myObj.Foo());
}
}
If you have a solution which contains for example Web Application and Test Project, you probably want that Test Project uses Web Application's web.config.
One way to solve it is to copy web.config to test project and rename it as app.config.
Another and better solution is to modify build chain and make it to make automatic copy of web.config to test projects output directory. To do that, right click Test Application and select properties. Now you should see project properties. Click "Build Events" and then click "Edit Post-build..." button. Write following line to there:
copy "$(SolutionDir)\WebApplication1\web.config" "$(ProjectDir)$(OutDir)$(TargetFileName).config"
And click OK. (Note you most probably need to change WebApplication1 as you project name which you want to test). If you have wrong path to web.config then copy fails and you will notice it during unsuccessful build.
Edit:
To Copy from the current Project to the Test Project:
copy "$(ProjectDir)bin\WebProject.dll.config" "$(SolutionDir)WebProject.Tests\bin\Debug\App.Config"
This is a bit old but I found a better solution for this. I was trying the chosen answer here but looks like .testrunconfig is already obsolete.
1. For Unit Tests, Wrap the config is an Interface (IConfig)
for Unit tests, config really shouldn't be part of what your testing so create a mock which you can inject. In this example I was using Moq.
Mock<IConfig> _configMock;
_configMock.Setup(config => config.ConfigKey).Returns("ConfigValue");
var SUT = new SUT(_configMock.Object);
2. For Integration test, dynamically add the config you need
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
if(config.AppSettings.Settings[configName] != null)
{
config.AppSettings.Settings.Remove(configName);
}
config.AppSettings.Settings.Add(configName, configValue);
config.Save(ConfigurationSaveMode.Modified, true);
ConfigurationManager.RefreshSection("appSettings");
This is very easy.
Right click on your test project
Add-->Existing item
You can see a small arrow just beside the Add button
Select the config file click on "Add As Link"
If you are using NUnit, take a look at this post. Basically you'll need to have your app.config in the same directory as your .nunit file.
If you application is using setting such as Asp.net ConnectionString you need to add the attribute HostType to your method, else they wont load even if you have an App.Config file.
[TestMethod]
[HostType("ASP.NET")] // will load the ConnectionString from the App.Config file
public void Test() {
}
I use NUnit and in my project directory I have a copy of my App.Config that I change some configuration (example I redirect to a test database...). You need to have it in the same directory of the tested project and you will be fine.
I couldn't get any of these suggestions to work with nUnit 2.5.10 so I ended up using nUnit's Project -> Edit functionality to specify the config file to target (as others have said it needs to be in the same folder as the .nunit file itself). The positive side of this is that I can give the config file a Test.config name which makes it much clearer what it is and why it is)
In my case, I performed the following steps to resolve my issue. I'm using Visual Studio Professional 2022, NUnit 3.13.3 and .NET 6.
I added an App.config file to the test project per the suggestions but ConfigurationManager.AppSettings still did not load any of my app settings.
In my unit test, I evaluated the value of ConfigurationManager.OpenExeConfiguration(System.Configuration.ConfigurationUserLevel.None).FilePath and determined that it was looking for a file named testhost.dll.config
In the unit test project, I renamed App.config to testhost.dll.config.
Your unit tests are considered as an environment that runs your code to test it. Just like any normal environment, you have i.e. staging/production. You may need to add a .config file for your test project as well. A workaround is to create a class library and convert it to Test Project by adding necessary NuGet packages such as NUnit and NUnit Adapter. it works perfectly fine with both Visual Studio Test Runner and Resharper and you have your app.config file in your test project.
And finally debugged my test and value from App.config: