问题
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.
回答1:
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.
回答2:
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.
回答3:
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
回答4:
You can both read and write to the app.config
file with the ConfigurationManager
class
回答5:
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/
回答6:
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.
回答7:
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);
}
回答8:
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).
回答9:
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.
回答10:
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?
回答11:
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."
回答12:
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
回答13:
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 ...
来源:https://stackoverflow.com/questions/168931/unit-testing-the-app-config-file-with-nunit