如何测试通过公共方法修改的私有字段

WDu*_*ffy 5 .net c# unit-testing

任何人都可以用一种建议的方法来指导我测试通过公共方法修改的类中的私有字段.我已经阅读了很多人的意见,建议不建议测试私有成员,因为它们是实现的内部,但是这种情况似乎与大多数其他答案不同.

我正在考虑使私有字段受到保护并创建一个公开该字段的测试子类,但如果我无法修改该类的内部,该怎么办?

在下面的示例代码中,要测试的私有成员将是_values,它是一个只写集合,通过AddValue()接收新值.

public class Sample
{

    private Dictionary<string, string> _values;
    private DateTime _created;

    public Sample()
    {
        _values = new Dictionary<string, string>();
        _created = DateTime.Now;
    }

    public void AddValue(string key, string value)
    {
        _values.Add(key, value);
    }
}
Run Code Online (Sandbox Code Playgroud)

sta*_*ica 2

我认为这将是依赖注入可能有所帮助的一个例子。

这里发生的情况是,您想要测试内部对象(字典_values)是否通过调用正确更新AddValue。您可以通过将模拟字典注入到被测类中来实现此目的。

这可以例如如下完成。首先,你必须Sample稍微改变一下你的课程:

public class Sample
{
    private IDictionary<string, string> _values = new Dictionary<string, string>();

    protected virtual IDictionary<string, string> GetDictionary()
    {
        return this._values;
    }

    public void AddValue(string key, string value)
    {
        GetDictionary().Add(key, value);
        //    ^^^
        // notice this!
    }
}
Run Code Online (Sandbox Code Playgroud)

Sample现在,您可以通过从类派生并通过覆盖该方法注入模拟字典,将默认字典替换为另一个字典(您可以在测试设置中观察到)InitializeDictionary

// this derived class is only needed in your test project:
internal class SampleTest : Sample
{
    public SampleTest(IDictionary<string, string> dictionaryToUse)
    {
        this._dictionaryToUse = dictionaryToUse;
    }

    private IDictionary<string, string> _dictionaryToUse;

    protected override IDictionary<string, string> GetDictionary()
    {
        return this._dictionaryToUse;
    }
}
Run Code Online (Sandbox Code Playgroud)

在您的测试设置中,您现在可以测试此类SampleTest而不是您的Sample类。这应该没问题,因为派生类是相同的,只是它允许您指定它将在内部使用的字典。用于检查的单元测试AddValue现在如下所示:

[Test]
public void AddValue_addSomething_DictionaryHasOneAdditionalEntry()
{
    var mockDictionary = new Dictionary<string, string>();
    var sample = new SampleTest(mockDictionary);
    var oldCount = mockDictionary.Count;

    sample.AddValue(...);

    Assert.AreEqual(oldCount + 1, mockDictionary.Count);
}
Run Code Online (Sandbox Code Playgroud)

免责声明:我绝不是单元测试专家,因此我的示例可能有缺陷,甚至过于复杂。我的目的只是为了证明,如果您以合理的测试方式设计类,那么您可以测试类的内部属性——例如,通过允许依赖注入的方式。