【问题标题】:How to stub out the dependency in a static class?如何消除静态类中的依赖关系?
【发布时间】:2014-09-10 10:21:48
【问题描述】:

我有一个静态类,我在其中读取 XML 来构建字典。 现在这个初始化是在静态构造函数中完成的。

为了测试这个 Initialize 方法,我必须以某种方式排除 XML 逻辑的读取,并给它一个 XDocument 进行测试,但不知道该怎么做。

 internal static class MasterMnemonicsLookup
    {

        private static Dictionary<string, StateCoverageMnemonic[]> masterMnemonics = new Dictionary<string, StateCoverageMnemonic[]>();


        private static StateCoverageMnemonic[] stateCoverageMnemonics;



        static MasterMnemonicsLookup()
        {
            Initialize();
        }

        private static void Initialize()
        {
            var resource = XDocument.Parse(GetResourceTextFile("MasterMnemonics.xml"));
            var serializer = new XmlSerializer(typeof (MasterMnemonicsType));
            var model = (MasterMnemonicsType) serializer.Deserialize(resource.CreateReader());

            var stateCoverageMnemonicsList = new List<StateCoverageMnemonic>();
            foreach (var masterMnemonic in model.MasterMnemonics)
            {
                var stateCoverageMnemonicsXml = new List<StateCoverageMnemonic>();

                var excludedStates = RiskStates.None;
                StateCoverageMnemonic allStateCoverageMnemonic = null;
                foreach (var stateCoverageMnemonic in masterMnemonic.StateCoverageMnemonics)
                {
                    var state = stateCoverageMnemonic.StateCode;
                    if (!state.HasFlag(RiskStates.All))
                    {
                        excludedStates = excludedStates | state;
                        var mnemonic = stateCoverageMnemonic.Mnemonic;
                        var coverageCode = stateCoverageMnemonic.CoverageCode;
                        var stateCoverageMnemonicTemp = new StateCoverageMnemonic(state, mnemonic, coverageCode);
                        stateCoverageMnemonicsXml.Add(stateCoverageMnemonicTemp);
                    }
                    else
                    {
                        //// TODO: If All occurs twice should we throw an exception
                        allStateCoverageMnemonic = new StateCoverageMnemonic(state, stateCoverageMnemonic.Mnemonic, stateCoverageMnemonic.CoverageCode);
                    }
                }

                if (allStateCoverageMnemonic != null)
                {
                    stateCoverageMnemonicsXml.Add(new StateCoverageMnemonic(RiskStates.All ^ excludedStates, allStateCoverageMnemonic.Mnemonic, allStateCoverageMnemonic.CoverageCode));
                }

                stateCoverageMnemonicsList.AddRange(stateCoverageMnemonicsXml);
                masterMnemonics.Add(masterMnemonic.MasterMnemonic, stateCoverageMnemonicsXml.ToArray());
            }

            stateCoverageMnemonics = stateCoverageMnemonicsList.ToArray();
        }

        private static string GetResourceTextFile(string filename)
        {
            string result = string.Empty;

            using (Stream stream = typeof(MasterMnemonicsLookup).Assembly.GetManifestResourceStream("Geico.Applications.Business.CoverageApi.DomainLayer.DataLayer." + filename))
            {
                var streamReader = new StreamReader(stream);
                result = streamReader.ReadToEnd();
            }
            return result;
        }
    }

【问题讨论】:

    标签: c# static-classes


    【解决方案1】:

    不建议以这种方式使用静态构造函数,您的场景就是一个很好的例子。您可以使用接受 XDocument 的公共实例构造函数来尝试单例模式。 (您可以使用内部,但这使得单元测试变得更加困难)。这是一种简单的依赖注入形式。

    对于测试,您的类的实例可以简单地由您的测试框架使用测试 XDocument 创建。

    对于您的实时应用程序,您的类的静态实例可以由容器类型初始化和保存,并且可以私下(在容器内)传入适当的 XDocument。

    【讨论】:

    • 我同意,最好将 MasterMnemonicsLookup 放入非静态类中,并在应用程序启动或延迟加载内容时,并在容器中保留对实例化的 MasterMnemonicsLookup 实例的引用。除了可能引发的异常之外,XmlSerializer 第一次执行序列化可能很耗时,因为它会在内部生成一个程序集来执行序列化。如果同时有其他线程正在加载一个类型,它们的静态构造函数将被暂时阻塞。
    • 我不明白如果我添加一个Instance构造函数,该类是如何单例的?
    • 类型本身不会是单例,但如果容器类型负责创建它的唯一实例,则可以将其视为单例。我假设这不是您正在创建的公共图书馆,因此它将是公共的而不是静态的这一事实并不重要。这是 Google 推荐的模式:例如,请参阅 googletesting.blogspot.com/2008/08/…
    【解决方案2】:

    我同意 Darious Vaughan-Scott

    但如果您想继续使用静态构造函数,您可能需要将加载逻辑放入一个单独的类中,这样更容易测试。

    例如

          internal class MasterMnemonicsLoader
          {
            public void Load(
                XDocument resource,
                Dictionary<string, StateCoverageMnemonic[]> masterMnemonics,
                StateCoverageMnemonic[] stateCoverageMnemonics)
            {
                //Do the loading here
    
            }
        }
    

    在 Initialize 方法中你可以调用 Load 方法

     private static void Initialize()
     {
        var resource = XDocument.Parse(GetResourceTextFile("MasterMnemonics.xml"));
        var loader = MasterMnemonicsLoader();
        loader.Load(resource, masterMnemonics, stateCoverageMnemonics);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-06
      • 2017-04-08
      • 1970-01-01
      • 2011-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多