如何对不可变类构造函数进行单元测试?

Posted

技术标签:

【中文标题】如何对不可变类构造函数进行单元测试?【英文标题】:How to unit test immutable class constructors? 【发布时间】:2008-09-25 00:09:13 【问题描述】:

我有一个不可变类,其中包含一些在构造函数执行期间设置的私有字段。我想对这个构造函数进行单元测试,但我不确定这种情况下的“最佳实践”。

简单示例

这个类在Assembly1中定义:

public class Class2Test

    private readonly string _StringProperty;

    public Class2Test()
    
        _StringProperty = ConfigurationManager.AppSettings["stringProperty"];
    

这个类是在Assembly2中定义的:

[TestClass]
public class TestClass

    [TestMethod]
    public void Class2Test_Default_Constructor()
    
        Class2Test x = new Class2Test();
        //what do I assert to validate that the field was set properly?
    

编辑 1:我已经用一个潜在的解决方案回答了这个问题,但我不确定这是否是“正确的方法”。因此,如果您认为自己有更好的想法,请发布。

这个例子真的不值得测试,但假设构造函数有一些更复杂的逻辑。最好的方法是避免测试构造函数并假设它在类上的方法的所有测试都有效的情况下有效吗?

编辑 2:看起来我让示例有点简单。我已经用更合理的情况更新了它。

【问题讨论】:

查看代码,我在其中找不到可能失败的语句。我看不出有什么理由需要对其进行测试。 我更新了示例。假设构造函数中有些东西可能会失败,我要测试的实际代码很长,我不想在这里粘贴。 【参考方案1】:

没有,除非您使用该字段。您不希望通过测试进行过度规范。换句话说,没有必要测试赋值运算符是否有效。

如果您在方法或其他内容中使用该字段,请调用该方法并对其进行断言。

编辑:

假设构造函数有一些更复杂的逻辑

您不应该在构造函数中执行任何逻辑。

编辑 2:

public Class2Test()

     _StringProperty = ConfigurationManager.AppSettings["stringProperty"];

不要那样做! =) 你的简单单元测试现在变成了集成测试,因为它依赖于多个类的成功运行。编写一个处理配置值的类。 WebConfigSettingsReader 可以是名称,它应该封装ConfigurationManager.AppSettings 调用。将该 SettingsReader 类的一个实例传递给Class2Test 的构造函数。然后,在您的单元测试中,您可以模拟您的WebConfigSettingsReader 并对您可能对其进行的任何调用做出响应。

【讨论】:

>>你不应该在构造函数中执行任何逻辑。如果我需要一些逻辑怎么办?放在哪里?【参考方案2】:

我已在 Assembly1(代码)上正确启用 [InternalsVisibleTo],以便与 Assembly2(测试)建立信任关系。

public class Class2Test

    private readonly string _StringProperty;
    internal string StringProperty  get  return _StringProperty;  

    public Class2Test(string stringProperty)
    
        _StringProperty = stringProperty;
    

这让我可以断言:

Assert.AreEqual(x.StringProperty, "something");

我唯一不喜欢的是,当您只查看Class2Test 时,并不清楚(没有评论)内部属性的用途是什么。

其他想法将不胜感激。

【讨论】:

【参考方案3】:

在您的编辑中,您现在依赖于难以测试的 ConfigurationManager。

一个建议是提取一个接口,然后让 Class2Test ctor 将 IConfigManager 实例作为参数。现在你可以使用一个 fake/mock 对象来设置它的状态,这样任何依赖于 Configuration 的方法都可以被测试,看看它们是否使用了正确的值......

    public interface IConfigManager
    
        string FooSetting  get; set; 
    

    public class Class2Test
    
        private IConfigManager _config;
        public Class2Test(IConfigManager configManager)
        
            _config = configManager;   
        

        public void methodToTest()
        
            //do something important with ConfigManager.FooSetting
            var important = _config.FooSetting;
            return important;
        
    

    [TestClass]
    public class When_doing_something_important
    
        [TestMethod]
        public void Should_use_configuration_values()
        
            IConfigManager fake = new FakeConfigurationManager();
            //setup state
            fake.FooSetting = "foo";
            var sut = new Class2Test(fake);
            Assert.AreEqual("foo", sut.methodToTest());
        
    

【讨论】:

感谢界面建议,我会用的。

以上是关于如何对不可变类构造函数进行单元测试?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用私有构造函数对类进行单元测试?

如何创建一个不可变类

如何创建一个不可变类

不可变构造函数注入 Kotlin 类的正确方法

不可变(数据)类上的多个构造函数

java中的不可变类型的探究