145

I am stuck at this point of code that I do not know how to mock:

ConfigurationManager.AppSettings["User"];

I have to mock the ConfigurationManager, but I don't have a clue, I am using Moq.

Someone can give me a tip? Thanks!

Joshua Enfield
  • 17,642
  • 10
  • 51
  • 98
Otuyh
  • 2,384
  • 5
  • 22
  • 40

9 Answers9

219

I am using AspnetMvc4. A moment ago I wrote

ConfigurationManager.AppSettings["mykey"] = "myvalue";

in my test method and it worked perfectly.

Explanation: the test method runs in a context with app settings taken from, typically a web.config or myapp.config. ConfigurationsManager can reach this application-global object and manipulate it.

Though: If you have a test runner running tests in parallel this is not a good idea.

LosManos
  • 7,195
  • 6
  • 56
  • 107
  • 10
    This is really clever and simple way to solve the problem! Kudos for the simplicity ! – Navap Oct 14 '16 at 02:11
  • 1
    Much easier than creating an abstraction in most cases – Michael Clark Oct 22 '16 at 14:38
  • 2
    That's it???? The brilliance is in the simplicity as I was racking my brain on how to test this particular sealed class. – Piotr Kula Feb 15 '17 at 11:53
  • This solution is great for "quick and dirty" unit tests until we properly refactor to a solution similar to the accepted solution. – Shay May 25 '17 at 22:30
  • Dear God...I'm so embarrassed that I didn't think of this. – Yatrix Jul 28 '17 at 19:28
  • 8
    `ConfigurationManager.AppSettings` is a `NameValueCollection` which is not thread-safe, so parallel tests using it without proper synchronization is not a good idea anyway. Otherwise you can just call `ConfigurationManager.AppSettings.Clear()` in your `TestInitialize` / ctor and you're golden. – Ohad Schneider Aug 08 '17 at 15:11
  • 1
    Simple and concise. By far the best answer! – znn Sep 07 '17 at 14:24
  • @OhadSchneider makes a good point ... you can also use `ConfigurationManager.RefreshSection("appSettings")` – Brett Veenstra Apr 12 '19 at 13:35
  • ConfigurationManager does not exist in the current context (?). I'm working with unit test and referenced project to a console – Leandro Bardelli Nov 10 '21 at 16:41
120

I believe one standard approach to this is to use a facade pattern to wrap the configuration manager and then you have something loosely coupled that you have control over.

So you would wrap the ConfigurationManager. Something like:

public class Configuration: IConfiguration
{
    public string User
    {
        get
        { 
            return ConfigurationManager.AppSettings["User"];
        }
    }
}

(You can just extract an interface from your configuration class and then use that interface everywhere in your code) Then you just mock the IConfiguration. You might be able to implement the facade itself in a few different ways. Above I chose just to wrap the individual properties. You also obtain the side benefit of having strongly typed information to work with rather than weakly typed hash arrays.

Sheridan
  • 68,826
  • 24
  • 143
  • 183
Joshua Enfield
  • 17,642
  • 10
  • 51
  • 98
  • 8
    This is conceptually what I am doing, too. However, I use Castle DictionaryAdapter (part of [Castle](http://www.castleproject.org) Core) which generates the implementation of the interface on the fly. I've written about it some time ago: http://blog.andreloker.de/post/2008/09/05/Getting-rid-of-strings-(3)-take-your-app-settings-to-the-next-level.aspx (scroll down to "A Solution" to see how I use Castle DictionaryAdapter) – Andre Loker Feb 28 '12 at 17:03
  • That is nifty and that is a good article. I'll have to keep this in mind for the future. – Joshua Enfield Feb 28 '12 at 18:24
  • I might also add - depending on your purism and interpretations - this could instead or also be called a Delegate Proxy or Adapter. – Joshua Enfield Apr 04 '12 at 18:24
  • 3
    From above it's just using Moq as "normal". Untested, but something like: `var configurationMock = new Mock();` and for the setup: `configurationMock.SetupGet(s => s.User).Returns("This is what the user property returns!");` – Joshua Enfield Oct 27 '16 at 17:07
  • This scenario is used when a layer is dependent on IConfiguration and you need to mock the IConfiguration, but how would you test the IConfiguration Implementation? And if you call in a Unit Test ConfigurationManager.AppSettings["User"] then this would not test the unit, but would test what values are fetched from the configuration file, which is not a unit test. If you need to check the implementation, see @ http://zpbappi.com/testing-codes-with-configurationmanager-appsettings/ – nkalfov Jan 31 '18 at 15:23
23

Maybe is not what you need to accomplish, but have you considered to use an app.config in your test project? So the ConfigurationManager will get the values that you put in the app.config and you don't need to mock anything. This solution works nice for my needs, because I never need to test a "variable" config file.

Iridio
  • 9,213
  • 4
  • 49
  • 71
  • 7
    If the behavior of the code under test changes depending on the value of a configuration value, it's certainly easier to test it if it does not depend on AppSettings directly. – Andre Loker Feb 28 '12 at 17:06
  • 2
    This is bad practice as you're never testing other possible settings. Joshua Enfield's answer is great for testing. – mkaj Jan 25 '15 at 06:29
  • 4
    While others are against this answer, I'd say their position is a bit generalized. This is a very valid answer in some scenarios and it really just depends on what you're needs are. For example, let's say I have 4 different clusters, each having a different base URL. Those 4 clusters are pulled, during runtime, from the `Web.config` encompassing the project. During testing, pulling some well known values from the `app.config` is very valid. The unit test just needs to make sure the conditions on when it pulls say "cluster1" works; there are only ever 4 different clusters in this case. – Mike Perrenoud Nov 16 '15 at 09:39
14

You can use shims to modify AppSettings to a custom NameValueCollection object. Here is an example of how you can achieve this:

[TestMethod]
public void TestSomething()
{
    using(ShimsContext.Create()) {
        const string key = "key";
        const string value = "value";
        ShimConfigurationManager.AppSettingsGet = () =>
        {
            NameValueCollection nameValueCollection = new NameValueCollection();
            nameValueCollection.Add(key, value);
            return nameValueCollection;
        };

        ///
        // Test code here.
        ///

        // Validation code goes here.        
    }
}

You can read more about shims and fakes at, Isolating Code Under Test with Microsoft Fakes. Hope this helps.

Zorayr
  • 23,770
  • 8
  • 136
  • 129
  • 7
    The author is asking for a how to with moq, not about MS Fakes. – JPCF Oct 17 '13 at 15:06
  • 6
    And how is this different? It achieves mocking by removing data dependency from his code. Using C# Fakes is one approach! – Zorayr Oct 20 '13 at 17:34
11

Have you considered stubbing instead of mocking? The AppSettings property is a NameValueCollection:

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        // Arrange
        var settings = new NameValueCollection {{"User", "Otuyh"}};
        var classUnderTest = new ClassUnderTest(settings);

        // Act
        classUnderTest.MethodUnderTest();

        // Assert something...
    }
}

public class ClassUnderTest
{
    private readonly NameValueCollection _settings;

    public ClassUnderTest(NameValueCollection settings)
    {
        _settings = settings;
    }

    public void MethodUnderTest()
    {
        // get the User from Settings
        string user = _settings["User"];

        // log
        Trace.TraceInformation("User = \"{0}\"", user);

        // do something else...
    }
}

The benefits are a simpler implementation and no dependency on System.Configuration until you really need it.

DanielLarsenNZ
  • 878
  • 9
  • 9
  • 3
    I like this approach the best. On one hand, wrapping the configuration manager with an `IConfiguration` as Joshua Enfield suggests can be too high level, and you might miss bugs that exist due to things like bad config value parsing. On the other hand, using `ConfigurationManager.AppSettings` directly as LosManos suggests is too much of an implementation detail, not to mention it can have side effects on other tests and cannot be used in parallel test runs without manual synchronization (as `NameValueConnection` is not thread safe). – Ohad Schneider Aug 08 '17 at 15:27
4

I fear I need to recall what I said. ConfigurationManager.AppSettings sporadically behaves strange, like if it would not always immediately yield the values just written. We had sporadic unit test failures on our build machines due to this. I had to rewrite my code to use a wrapper, returning ConfigurationManager.AppSettings in the usual case and test values in unit tests.

How about just setting what you need? Because, I don't want to mock .NET, do I...?

System.Configuration.ConfigurationManager.AppSettings["myKey"] = "myVal";

You probably should clean out the AppSettings beforehand to make sure the app only sees what you want it to.

Eike
  • 1,167
  • 10
  • 12
3

That is a static property, and Moq is designed to Moq instance methods or classes that can be mocked via inheritance. In other words, Moq is not going to be any help to you here.

For mocking statics, I use a tool called Moles, which is free. There are other framework isolation tools, like Typemock that can do this too, though I believe those are paid tools.

When it comes to statics and testing, another option is to create the static state yourself, though this can often be problematic (as, I'd imagine it would be in your case).

And, finally, if the isolation frameworks are not an option and you're committed to this approach, the facade mentioned by Joshua is a good approach, or any approach in general where you factor client code of this away from the business logic that you're using to test.

Erik Dietrich
  • 6,080
  • 6
  • 26
  • 37
1

Another way to achieve this goal is to just provide your own IConfiguration, pulling from any file you'd like it to pull from, like this:

var builder = new ConfigurationBuilder()
         .SetBasePath(Directory.GetCurrentDirectory())
         .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true).Build();

Now, as long as you have the values you need for testing in this JSON file, it's very easy to override and change values.

FoxDeploy
  • 12,569
  • 2
  • 33
  • 48
0

I think writing you own app.config provider is a simple task and is more useful then anything else. Especially you should avoid any fakes like shims etc. because as soon as you use them Edit & Continue no longer works.

The providers I use look like this:

By default they get the values from the App.config but for unit tests I can override all values and use them in each test independently.

There's no need for any interfaces or implement it each time over and over again. I have a utilities dll and use this small helper in many projects and unit tests.

public class AppConfigProvider
{
    public AppConfigProvider()
    {
        ConnectionStrings = new ConnectionStringsProvider();
        AppSettings = new AppSettingsProvider();
    }

    public ConnectionStringsProvider ConnectionStrings { get; private set; }

    public AppSettingsProvider AppSettings { get; private set; }
}

public class ConnectionStringsProvider
{
    private readonly Dictionary<string, string> _customValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

    public string this[string key]
    {
        get
        {
            string customValue;
            if (_customValues.TryGetValue(key, out customValue))
            {
                return customValue;
            }

            var connectionStringSettings = ConfigurationManager.ConnectionStrings[key];
            return connectionStringSettings == null ? null : connectionStringSettings.ConnectionString;
        }
    }

    public Dictionary<string, string> CustomValues { get { return _customValues; } }
}

public class AppSettingsProvider
{
    private readonly Dictionary<string, string> _customValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

    public string this[string key]
    {
        get
        {
            string customValue;
            return _customValues.TryGetValue(key, out customValue) ? customValue : ConfigurationManager.AppSettings[key];
        }
    }

    public Dictionary<string, string> CustomValues { get { return _customValues; } }
}
t3chb0t
  • 16,340
  • 13
  • 78
  • 118