代码之家  ›  专栏  ›  技术社区  ›  Jeff Meatball Yang

Visual Studio 2008-使用Web配置设置进行单元测试

  •  2
  • Jeff Meatball Yang  · 技术社区  · 16 年前

    我的web应用程序依赖于web.config条目是一个特定的值(比如feature_activated=true),那么如何测试读取该web.config条目的函数呢?

    我希望避免将web.config条目复制到单元测试项目中的app.config中,因为同步文件需要额外的工作。

    3 回复  |  直到 16 年前
        1
  •  4
  •   NerdFury    16 年前

    拉出读取配置数据的代码,然后在测试中使用与模拟对象或模拟框架配对的依赖注入。

    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();
    }
    
        2
  •  1
  •   Oded    16 年前

    我也喜欢尽可能避免使用这些代码,但有时没有其他的选择(特别是在处理遗留代码时)。

    在可以的地方,创建一个用于访问配置选项的接口-将其插入正在访问配置的任何位置。

    然后实现一个具体的类,将其委托给内置的配置类,这是要使用的默认实现。

    为测试创建接口的模拟实现,并在测试时注入。

        3
  •  1
  •   Page    16 年前

    我总是包装配置逻辑,以便在系统测试时替换(模拟)配置。

    换句话说,我的配置是这样包装的:

        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; }
            }
    }
    

    然后,当系统处于测试状态时,我可以这样模拟我的配置:

    var settings = new Mock<IConfigurationSettings>();
    settings.SetupGet(s => s.SmtpHost).Returns("127.0.0.1");
    Resolver.Setup(r => r.Resolve<IConfigurationSettings>()).Returns(settings.Object);