The configSource
element solution given by MarkLawrence is what I was looking for, and works nicely. The challenge in implementing this solution however, is to make the assembly configuration load when running tests from both an explicit NUnit project (as in my case), AND when running the unit tests for an assembly in isolation (no explicit project). To accomplish this, the following modifications to my file layout were required.
+ TestFolder
testProject.nunit
testProject.config
+ AssemblyAFolder
assemblyA.dll
assemblyA.dll.config
assemblyA.dll.configfragment
+ AssemblyBFolder
assemblyB.dll
assemblyB.dll.config
assemblyB.dll.configfragment
The configfragment
files are created to contain the assembly configuration that was once in the corresponding config
files. Afterwards, the config
files are modified to contain only a configSource
element with a relative path to the corresponding configfragment
file. Note that the only time that this approach doesn't work is when assemblyA.dll
and assemblyB.dll
both require the same configuration section, as a conflict will arise when creating testproject.config
.
After experimenting with this approach I decided to rely on generating the assembly configuration at runtime, and remove the static configuration files all together. Here is some code that demonstrates how to generate the configuration, and make it accessible regardless of how the assembly-under-test is loaded.
void WithConfigurationFile(Action method)
{
// Create the assembly configuration.
string settingsSection = "myConfigSectionName";
Configuration config =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.Sections.Add(
settingsSection,
new ConfigSectionType(/*config element values*/);
config.Save();
try
{
// Invoke the method with the new configuration.
ConfigurationManager.RefreshSection(settingsSection);
method();
}
finally
{
// Revert the assembly configuration.
File.Delete(config.FilePath);
ConfigurationManager.RefreshSection(settingsSection);
}
}
By using the ConfigurationManager.OpenExeConfiguration() overload that does not accept a path, we load the configuration from the host application's working directory, which changes depending on how you run your NUnit tests. Also, the try/finally block guarantees that your assembly configuration will not interfere with other tests, which may or may not require such configuration.
Finally, to use within a unit test:
[Test]
void VerifyFunctionality
{
WithConfigurationFile(delegate
{
// implement unit test and assertions here
});
}
I hope this helps others who may have encountered similar issues!