• ASP.NET 系列:单元测试之ConfigurationManager


    通过ConfigurationManager使用.NET配置文件时,可以通过添加配置文件进行单元测试,虽然可以通过测试但达不到解耦的目的。使用IConfigurationManager和ConfigurationManagerWrapper对ConfigurationManager进行适配是更好的方式,ConfigurationManagerWrapper提供.NET配置文件方式的实现,如果需要支持其他配置,创建IConfigurationManager接口的不同的实现类即可。

    1.定义IConfigurationManager接口

    原本依赖ConfigurationManager的代码现在依赖IConfigurationManager。可以在单元测试时方便的Mock。

    public interface IConfigurationManager
    {
        NameValueCollection AppSettings { get; }
        ConnectionStringSettingsCollection ConnectionStrings { get; }
        object GetSection(string sectionName);
    }

    2.创建适配类ConfigurationManagerWrapper

    非单元测试环境使用ConfigurationManagerWrapper作为IConfigurationManager的默认实现。

    public class ConfigurationManagerWrapper : IConfigurationManager
    {
        public NameValueCollection AppSettings
        {
            get
            {
                return ConfigurationManager.AppSettings;
            }
        }
    
        public ConnectionStringSettingsCollection ConnectionStrings
        {
            get
            {
                return ConfigurationManager.ConnectionStrings;
            }
        }
    
        public object GetSection(string sectionName)
        {
            return ConfigurationManager.GetSection(sectionName);
        }
    }

    3.自定义泛型配置接口

    在我们的代码需要使用配置时,可以考虑创建通用的泛型接口也可以使用专用的强类型的接口。这里演示使用通用的接口。

    public interface IConfiguration
    {
        T Get<T>(string key, T @default);
    }

    4.实现泛型接口配置接口的.NET配置文件版本

    AppConfigAdapter直接不使用ConfigurationManager而是依赖IConfigurationManager接口。

    public class AppConfigAdapter : IConfiguration
    {
        private IConfigurationManager _configurationManager;
    
        public AppConfigAdapter(IConfigurationManager configurationManager)
        {
            this._configurationManager = configurationManager;
        }
    
        public T Get<T>(string nodeName, T @default)
        {
            var value = this._configurationManager.AppSettings[nodeName];
            return value == null ? @default : (T)Convert.ChangeType(value, typeof(T));
        }
    }

    5.对泛型配置接口的实现进行单元测试

    使用最流行的单元测试框架和Mock类库:xUnit+Moq进行单元测试。

    public class AppConfigAdapterTest
    {
        [Fact]
        public void GetStringTest()
        {
            var key = "key";
            var value = "value";
            var configuration = new AppConfigAdapter(this.GetConfigurationManager(o => o.Add(key, value.ToString())));
            Assert.Equal(configuration.Get(key, string.Empty), value);
        }
    
        [Fact]
        public void GetIntTest()
        {
            var key = "key";
            var value = 1;
            var configuration = new AppConfigAdapter(this.GetConfigurationManager(o => o.Add(key, value.ToString())));
            Assert.Equal(configuration.Get(key, int.MinValue), value);
        }
    
        [Fact]
        public void GetBoolTest()
        {
            var key = "key";
            var value = true;
            var configuration = new AppConfigAdapter(this.GetConfigurationManager(o => o.Add(key, value.ToString())));
            Assert.Equal(configuration.Get(key, false), value);
        }
    
        [Fact]
        public void GetDateTimeTest()
        {
            var key = "key";
            var value = DateTime.Parse(DateTime.Now.ToString());
            var configuration = new AppConfigAdapter(this.GetConfigurationManager(o => o.Add(key, value.ToString())));
            Assert.Equal(configuration.Get(key, DateTime.MinValue), value);
        }
    
        [Fact]
        public void GetDecimalTest()
        {
            var key = "key";
            var value = 1.1m;
            var configuration = new AppConfigAdapter(this.GetConfigurationManager(o => o.Add(key, value.ToString())));
            Assert.Equal(configuration.Get(key, decimal.MinValue), value);
        }
    
        private IConfigurationManager GetConfigurationManager(Action<NameValueCollection> set)
        {
            var appSettings = new NameValueCollection();
            set(appSettings);
            var configurationManager = new Mock<IConfigurationManager>();
            configurationManager.Setup(o => o.AppSettings).Returns(appSettings);
            return configurationManager.Object;
        }
    }

    运行结果:

    6.总结

    使依赖ConfigurationManager静态类的代码转换为依赖IConfigurationManager接口,运行时注入ConfigurationManagerWrapper实现类。单元测试时使用Mock模拟IConfigurationManager对象。

  • 相关阅读:
    文件操作
    内置函数
    lambda表达式
    函数基础
    基础数据类型-dict
    基础数据类型-tuple
    基础数据类型-list
    基础数据类型-set
    Python开发【第三篇】基本数据类型
    Python开发【第二篇】运算符
  • 原文地址:https://www.cnblogs.com/easygame/p/5176711.html
Copyright © 2020-2023  润新知