2

I have reduced this to the simplest possible.

VS2019 MSTest Test Project (.NET Core) template

Default unit test project .

Use nuget to install System.Configuration.ConfigurationManager(5.0.0)

Add app.config file to project (add -> new Item -> select Application Configuration File>

Add entry to config file.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
  <add key="TestKey" value="testvalue"/>
</appSettings>
</configuration>

Debug the code below and k is null.

   using Microsoft.VisualStudio.TestTools.UnitTesting;
   using System.Configuration;

   namespace UnitTestProject1
   {
    [TestClass]
    public class UnitTest1
    {
    [TestMethod]
    public void TestMethod1()
    {
        var k = System.Configuration.ConfigurationManager.AppSettings["TestKey"];

    }
  }
 

How do you get the unit test to read the config file?

Bob Clegg
  • 553
  • 2
  • 9
  • 21
  • AppSettings.Settings["TestKey"] ? – agent_bean Dec 16 '20 at 22:51
  • It feels like a weird use case. Can you add some context around what your trying to achieve, I might be wrong but my gut says there is a better way. Be well. – gingerbreadboy Dec 16 '20 at 22:59
  • 1
    To expand on the above. If it's a unit test why not just define this value in the test? You don't need to test the value is correctly picked from the config file, so what benefit does doing this add. I dunno, I don't have context so I may be taking rubbish and that's fine, but it *feels* wrong. – gingerbreadboy Dec 16 '20 at 23:01
  • Looks like this issue were discussed at https://stackoverflow.com/questions/344069/can-a-unit-test-project-load-the-target-applications-app-config-file – Prasad Ramireddy Dec 16 '20 at 23:19
  • The real world use is a unit test for a chunk of code that has a config value read deep in it. Still can't that going but with new info from these answers I am hopeful. – Bob Clegg Dec 18 '20 at 02:51
  • Again, I don't have all the context, but I would want to be thinking about refactoring this up and out **if possible**. Feels like your DI/IOC isn't quite right. I know, is not always possible with legacy code so YMMV :) – gingerbreadboy Dec 19 '20 at 09:59

3 Answers3

5

If you add this line to your TestMethod, it will tell you what is the name of the config file it is expecting to use:

public void TestMethod1()
{
    string path = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).FilePath;
    var k = ConfigurationManager.AppSettings["TestKey"];
}

When I ran it, it called the file "(path-to)\testhost.dll.config", not "App.config". So all I did was rename the file to "testhost.dll.config", change its Build Action to "Content" and "Copy always", ran the unit test, and it gave me the right value in var k.

I can't explain why it would look specifically for that filename, but for some reason it is.

Tam Bui
  • 2,940
  • 2
  • 18
  • 27
  • path was C:\temp\Projects Testing\UnitTestProject1\bin\Debug\netcoreapp3.1 File was ReSharperTestRunner64.dll.config. Soo obvious how did I miss it. Thank you – Bob Clegg Dec 17 '20 at 07:10
  • Hahaha, exactly! Soo obvious. Why haven't you submitted that filename to memory yet? You're going to need it five years from now. – Tam Bui Dec 17 '20 at 17:51
  • 2
    Just wasted an hour on this until I found your answer. Thank you. – danny10846 Feb 24 '22 at 14:42
  • It's important to note that loading a config file with "OpenMappedMachineConfiguration" causes it to disregard the AppSettings section, such that it doesn't how to cast that section to the AppSettingsSection type. – Brandon Hawbaker Jul 13 '23 at 20:12
2

You have to tell the configuration manager what file to load. Don't rely on the file matching the exe name, etc. Just keep the name as app.config.

System.Configuration.ConfigurationFileMap configMap = new ConfigurationFileMap("./app.config");
System.Configuration.Configuration configuration = System.Configuration.ConfigurationManager.OpenMappedMachineConfiguration(configMap);
string value = configuration.AppSettings["TestKey”];
jjxtra
  • 20,415
  • 16
  • 100
  • 140
-1

I was facing a similar situation where my unit tests were unable to access the app.config and the appropriate "appSettings" section. In my case, the solution mentioned above loading the OpenMappedMachineConfiguration doesn't work because it didn't know how to cast the AppSettings section, thinking it was a machine config file rather than a normal application config file.

To explicitly load a file for an application expecting the "appSettings" section, this method works better:

 Configuration configuration = System.Configuration.ConfigurationManager.OpenExeConfiguration("./App.exe");
string value = configuration.AppSettings.Settings["test"].Value;

By specifying the application name, it automatically adds the suffix ".config" like "App.exe.config", which is the name of the generated file. This approach of loading configuration is useful when you want to explicitly load a separate config, such as from a linked application.

However, in my case, I also noticed that just by removing the existing configs and readding them as you did originally (add -> new Item -> select Application Configuration File), the file would then properly generate the [AppName].dll.config relative to the test project assembly, which appears to be why yours started working after that, because the file was not in the bin/Debug folder with the proper naming convention. Once the file is being generated properly in the output directory, the normal syntax begins working again:

string test = ConfigurationManager.AppSettings["test"];

It's not clear why the file did not originally generate properly and it began relying upon a "Microsoft Visual Studio\2019\Enterprise\Common7\IDE\Extensions\TestPlatform\testhost.net462.x86.exe.config" file instead.

Perhaps, it wasn't actually in the output directory at the time it was added to the project and the test was run. This appears to be a bug in Visual Studio where it fails to regenerate the missing config file if it was missing and the application itself hasn't changed. I could reproduce this issue, by manually deleting just the [App].dll.config file from bin/debug and rerunning the test. Even building the project over again does not regenerate the .config file. To regenerate it, I had to explicitly run the "Rebuild" option, but how we ran into this bug isn't clear at this time.