ChatGPT解决这个技术问题 Extra ChatGPT

使用 NUnit 对 app.config 文件进行单元测试

When you guys are unit testing an application that relies on values from an app.config file? How do you test that those values are read in correctly and how your program reacts to incorrect values entered into a config file?

It would be ridiculous to have to modify the config file for the NUnit app, but I can't read in the values from the app.config I want to test.

Edit: I think I should clarify perhaps. I'm not worried about the ConfigurationManager failing to read the values, but I am concerned with testing how my program reacts to the values read in.


M
Mendelt

I usually isolate external dependencies like reading a config file in their own facade-class with very little functionality. In tests I can create a mock version of this class that implements and use that instead of the real config file. You can create your own mockup's or use a framework like moq or rhino mocks for this.

That way you can easily try out your code with different configuration values without writing complex tests that first write xml-configuration files. The code that reads the configuration is usually so simple that it needs very little testing.


It's scary to see that this answer hasn't got more upvotes and that other answers talking about adding/reading/editing config files have so many points. To readers, this answer is the way to go and keep your unit tests simple and SOLID.
"There is no problem that can't be solved by adding another layer of abstraction." :-)
@lain "Except for the problem of too many layers of abstraction" :)
S
SteveC

You can modify your config section at runtime in your test setup. E.g:

// setup
System.Configuration.Configuration config = 
     ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.Sections.Add("sectionname", new ConfigSectionType());
ConfigSectionType section = (ConfigSectionType)config.GetSection("sectionname");
section.SomeProperty = "value_you_want_to_test_with";
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("sectionname");

// carry out test ...

You can of course setup your own helper methods to do this more elegantly.


Reading a file from disk makes the whole test suite turn into integration tests though. You are no longer unit testing since there is global state and external dependencies used.
P
Pervez Choudhury

You can call the set method of ConfigurationManager.AppSettings to set the values required for that particular unit test.

[SetUp]
public void SetUp()
{
  ConfigurationManager.AppSettings.Set("SettingKey" , "SettingValue");
  // rest of unit test code follows
}

When the unit test runs it will then use these values to run the code


This was by far the easiest way to solve it for my purposes. My code just checked if the key named Environment was TEST or LIVE. So I just set the key to TEST at the beginning of the unit test method.
S
SteveC

You can both read and write to the app.config file with the ConfigurationManager class


Ahhh, so I can set values in the ConfigurationManager collection? I always assumed it was read-only. I guess that's what I get for making assumptions :P
I just tried this, and it works great! For example, ConfigurationManager.AppSettings["SomeKey"] = "MockValue";. Good answer!
When I tried it does change the value of the key u specify but also removes values and all other keys :(
@Yasser: Mendelt's solution is better ;)
@StevenA.Lowe I ended up using red Pervez Choudhury solution :)
S
SteveC

I was facing similar problems with web.config.... I find an interesting solution. You can encapsulate configuration reading function, e.g. something like this:

public class MyClass {

public static Func<string, string> 
     GetConfigValue = s => ConfigurationManager.AppSettings[s];

//...

}

And then normally use

string connectionString = MyClass.GetConfigValue("myConfigValue");

but in unit test initialize "override" the function like this:

MyClass.GetConfigValue = s =>  s == "myConfigValue" ? "Hi", "string.Empty";

More about it:

http://rogeralsing.com/2009/05/07/the-simplest-form-of-configurable-dependency-injection/


佚名

A more elegant solution is to use plain old dependency injection on the configuration settings themselves. IMHO this is cleaner than having to mock a configuration reading class/wrapper etc.

For example, say a class "Weather" requires a "ServiceUrl" in order to function (e.g. say it calls a web service to get the weather). Rather than having some line of code that actively goes to a configuration file to get that setting (whether that code be in the Weather class or a separate configuration reader that could be mocked as per some of the other responses), the Weather class can allow the setting to be injected, either via a parameter to the constructor, or possibly via a property setter. That way, the unit tests are extremely simple and direct, and don't even require mocking.

The value of the setting can then be injected using an Inversion of Control (or Dependency Injection) container, so the consumers of the Weather class don't need to explicitly supply the value from somewhere, as it's handled by the container.


S
SteveC

That worked for me:

 public static void BasicSetup()
  {
     ConnectionStringSettings connectionStringSettings = 
          new ConnectionStringSettings();
     connectionStringSettings.Name = "testmasterconnection";
     connectionStringSettings.ConnectionString = 
          "server=localhost;user=some;database=some;port=3306;";
     ConfigurationManager.ConnectionStrings.Clear();
     ConfigurationManager.ConnectionStrings.Add(connectionStringSettings);
  }

Y
Yuval

You can always wrap the reading-in bit in an interface, and have a specific implementation read from the config file. You would then write tests using Mock Objects to see how the program handled bad values. Personally, I wouldn't test this specific implementation, as this is .NET Framework code (and I'm assuming - hopefully - the MS has already tested it).


j
jakejgordon

System.Configuration.Abstractions is a thing of beauty when it comes to testing this kind of stuff.

Here is the GitHub project site with some good examples: enter link description here

Here is the NuGet site: https://www.nuget.org/packages/System.Configuration.Abstractions/

I use this in almost all of my .NET projects.


D
Dana

Actually, thinking on it further, I suppose what I should do is create a ConfigFileReader class for use in my project and then fake it out in the unit test harness?

Is that the usual thing to do?


T
Travis Illig

The simplest option is to wrap the methods that read configuration such that you can substitute in values during testing. Create an interface that you use for reading config and have an implementation of that interface get passed in as a constructor parameter or set on the object as a property (as you would using dependency injection/inversion of control). In the production environment, pass in an implementation that really reads from configuration; in the test environment, pass in a test implementation that returns a known value.

If you don't have the option of refactoring the code for testability yet still need to test it, Typemock Isolator provides the ability to actually mock the .NET framework configuration classes so you can just say "next time I ask for such-and-such appSettings value, return this known value."


s
sundar venugopal

I had the same issue,

you can use Nunit-console.exe c:\path1\testdll1.dll c:\path2\testdll2.dll

this works fine even though if both dlls point to different app.configs ex testdll1.dll.config and testdll2.dll.config

if you want to use Nunit project config and wrap these two dlls then there is no way you can have two configs

you have to have project1.config if your Nunit project is project1.nunit in the same location as Project1.nunit sits.

hope this helps


u
user798990

Well, I just had the same problem... I wanted to test a BL project that is referenced from a web site . but i wanted to test the BL only. So in the pre-build event of the test project I copy the app.Config files into the bin\debug folder and reference them from the app.config ...


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅