views:

189

answers:

3

My web application depends on a web.config entry being a certain value (like FEATURE_ACTIVATED=true) so how do I test the function that reads this web.config entry?

I'd like to avoid copying the web.config entries to an app.config in the unit testing project, as it takes extra effort to synchronize the files.

+1  A: 

I also like avoiding these where possible, but sometimes there are not other options (particularly when working with legacy code).

Where you can, create an interface for accessing configuration options - inject it into any place you are accessing configuration.

Then implement a concrete class that delegates that to the built in configuration classes, that's the default implementation to use.

Create a mock implementation of the interface for your testing and inject that when testing.

Oded
+1  A: 

I always wrap the configuration logic so that I can replace (mock) the configuration while the system is under test.

In other words, I wrap my configuration like so:

    public interface IConfigurationSettings
    {
        string SmtpHost { get; }
    }

    public class ConfigurationSettings : IConfigurationSettings
    {
        public string SmtpHost
        {
            get { return ConfigurationManager.AppSettings["SmtpHost"]; }
        }
    }

    public static class Settings
    {
        private static readonly IConfigurationSettings _configurationSettings;

        static Settings()
        {
            _configurationSettings = IoCHelper.Resolve<IConfigurationSettings>();
        }

        public static string SmtpHost
        {
            get { return _configurationSettings.SmtpHost; }
        }
}

Then, when the system is under test, I can just mock out my configuration like so:

var settings = new Mock<IConfigurationSettings>();
settings.SetupGet(s => s.SmtpHost).Returns("127.0.0.1");
Resolver.Setup(r => r.Resolve<IConfigurationSettings>()).Returns(settings.Object);
Page Brooks
+2  A: 

Pull out the code that reads configuration data, then use dependency injection paired with a mock object, or a mocking framework in your tests.

public interface IConfiguration
{
  bool IsAwesomeFeatureActivated { get; }
}

public class Configuration: IConfiguration
{
  public bool IsAwesomeFeatureActivated
  { 
    get { /* get config value */ }
  }
}

public class AwesomeFeature
{
  private IConfiguration _configuration;

  public AwesomeFeature(IConfiguration configuration)
  {
    _configuration = configuration;
  }

  public void ExecuteFeature()
  {
    if(! _configuration.IsAwesomeFeatureActivated) return;
    // do awesome feature functionality
  }
}

public class MockConfiguration: IConfiguration
{
  private bool _isAwesomeFeatureActivated;
  public void SetIsAwesomeFeatureEnabled(bool value)
  {
    _isAwesomeFeatureActivated = value;
  }

  public bool IsAwesomeFeatureActivated
  {
    get { return _isAwesomeFeatureActivated; }
  }
}

// with mock object
[Test]
public void ExecuteFeature_WhenNotActivated_DoNothing()
{
  var mockConfig = new MockConfiguration();
  mockConfig.SetIsAwesomeFeatureActivated(false);
  var feature = new AwesomeFeature(mockConfig);
  feature.ExecuteFeature();
  Assert.SomethingHere();
}

// or with Moq framework
[Test]
public void ExecuteFeature_WithActivated_DoSomething()
{
  var mock = new Mock<IConfiguration>();
  mock.Setup(c => c.IsAwesomeFeatureActivated).Returns(true);

  var feature = new AwesomeFeature(mock.Object);
  feature.ExecuteFeature();

  Assert.SomethingHere();
}
NerdFury