【问题标题】:unit test static constructor w/ different config values具有/不同配置值的单元测试静态构造函数
【发布时间】:2012-07-01 04:27:37
【问题描述】:

我有一个带有静态构造函数的类,我用它来读取 app.config 值。如何对具有不同配置值的类进行单元测试。我正在考虑在不同的应用程序域中运行每个测试,这样我就可以为每个测试执行静态构造函数 - 但我在这里有两个问题:
1. 我不知道如何在单独的应用程序域中运行每个测试运行
2. 如何在运行时更改配置设置?

有人可以帮我解决这个问题吗?或者有人有更好的解决方案吗?谢谢。

【问题讨论】:

  • 将该逻辑提取到一个非静态类中,然后从 cctor 中调用它。现在你可以测试这个新类了。

标签: c# unit-testing static-constructor


【解决方案1】:

就我个人而言,我只是将您的静态构造函数放入静态方法中,然后在静态块中执行该方法。

【讨论】:

    【解决方案2】:

    您无需测试 .Net 即可从配置文件加载数据。
    相反,试着专注于测试你自己的逻辑。

    更改您的类,使其从其构造函数(或通过属性)获取配置值,然后像使用任何其他依赖项一样对其进行测试。

    在此过程中,您还将班级移至SRP

    根据配置加载 - 将此逻辑集中在一个单独的非静态类中。


    编辑:
    将配置逻辑分离到另一个类中。像这样:

    public static class ConfigurationLoader
    {
        static ConfigurationLoader()
        {
            // Dependency1 = LoadFromConfiguration();
            // Dependency2 = LoadFromConfiguration();
        }
    
        public static int Dependency1 { get; private set; }
        public static string Dependency2 { get; private set; }
    }
    

    然后,当您实例化您的类时,将其注入依赖项:

    public class MyClass
    {
        private readonly int m_Dependency1;
        private readonly string m_Dependency2;
    
        public MyClass(int dependency1, string dependency2)
        {
            m_Dependency1 = dependency1;
            m_Dependency2 = dependency2;
        }
    
        public char MethodUnderTest()
        {
            if (m_Dependency1 > 42)
            {
                return m_Dependency2[0];
            }
    
            return ' ';
        }
    }
    
    public class MyClassTests
    {
        [Fact]
        public void MethodUnderTest_dependency1is43AndDependency2isTest_ReturnsT()
        {
            var underTest = new MyClass(43, "Test");
            var result = underTest.MethodUnderTest();
            Assert.Equal('T', result);
        }
    }
    
    ...
    
    var myClass = new MyClass(ConfigurationLoader.Dependency1, ConfigurationLoader.Dependency2);
    

    您可以继续使用 IOC 容器,但是通过这种简单的可测试设计解决了使用不同输入测试 MyClass 的问题。

    【讨论】:

    • 感谢您的回复。但是我们使用静态构造函数来避免在每次调用时从配置值中读取值。我正在编写的单元测试不是为了测试 .NET 是否能够从配置文件中加载数据,而是为了测试具有不同值的方法的行为。
    【解决方案3】:

    如果您从(Web)ConfigurationManager.AppSettings 读取,那只是一个NameValueCollection,因此您可以将读取ConfigurationManager.AppSettings 的代码直接替换为从任何NameValueCollection 读取的代码。

    只需将您的实际配置解析从静态 ctor 移至静态方法即可。静态 ctor 调用该静态方法并传递 ConfigurationManager.AppSettings,但您可以从测试代码中调用该解析器方法,并验证配置解析,而无需实际接触文件或弄乱应用程序域。

    但从长远来看,确实按照 seldary 的建议注入您的配置参数。创建一个配置类,在应用程序启动时读取实际值,并设置您的 IoC 容器以向所有请求者提供相同的配置实例。

    这也使进一步的测试更容易,因为您的类不会从全局静态配置实例中读取。您可以只传递特定的配置实例以进行不同的测试。当然要为你的测试创建一个工厂方法,来构造一个全局配置,这样你就不必一直手动去做......

    【讨论】:

      【解决方案4】:

      我最近遇到了同样的问题。唯一的区别是配置值来自数据库而不是 app.config。我能够使用 TypeInitializer 解决它。

      [Test]
      public void TestConfigurationInStaticConstructor()
      {
          // setup configuraton to test
          // ...
      
          // init static constructor
          ReaderTypeInit();
      
          // Assert configuration effect
          // ...
      
          // reset static ctor to prevent other existing tests (that may depend on original static ctor) fail
          ReaderTypeInit();
      }
      
      // helper method
      private void ReaderTypeInit()
      {
          typeof(< your class with static ctor>).TypeInitializer.Invoke(null, new object[0]);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多