如何才能正确地将相互依赖的测试方法单元化?

rye*_*guy 7 c# unit-testing

考虑以下代码:

    private readonly Dictionary<Type, Component> _components = new Dictionary<Type, Component>();

    public Component this [Type type]
    {
        get
        {
            Component component;
            _components.TryGetValue(type, out component);
            return component;
        }
    }

    public void AddComponent(Component component)
    {
        _components.Add(component.GetType(), component);
    }
Run Code Online (Sandbox Code Playgroud)

如您所见,AddComponent添加到私有_components变量.但测试这种情况的唯一方法是使用索引器.那很好,但为了测试索引器,我也必须打电话AddComponent!

换句话说,在索引器的单元测试中AddComponent,每个测试都必须调用这两种方法.这似乎是在创造不必要的耦合.如果索引器中存在错误,则没有理由让我TestAddComponent失败.

这里的最佳做法是什么?我是否使用反射来获取_components?惩戒?别的什么?

Mig*_*elo 7

在我看来,单元测试不应该反思强迫它的目标.我认为在这种测试中,两者都应该在同一测试中进行测试.但这只是一个观点.

但是,您可以进行多项测试,更改指令的顺序.尝试添加多个,然后访问第一个,然后是最后一个,然后是中间的一个.每个测试都是一个场景,具有不同的顺序,插入次数.您甚至可以测试必须发生的异常状态...例如,如果您尝试获取未插入的内容.

我认为单元测试的存在是为了模仿使用或强制执行规范.不要看是否该程序的每一位都是正确的,因为这会杀死灵活性.


Jus*_*tin 6

那你有两个选择:

  1. 使用反射或MSTest私有访问器类在测试期间获取和设置私有字段值.
  2. 只是不要担心它并测试暴露的行为,即使这意味着您的测试依赖于其他地方正在测试的其他属性或方法.

你可以从措辞中看出,我的选择是#2 - 你应该测试暴露的行为.在您的情况下,您正在测试的暴露行为是:

  • 如果我使用,AddComponent那么添加的组件应该可以通过索引器访问
  • 如果我使用索引器,我应该能够访问通过添加的任何组件 AddComponent

在这种情况下,很明显这些几乎是相同的,所以我们只有一个单元案例/暴露行为来测试这里.是的,这个单元测试包含两个不同的东西,但这并不重要 - 我们不是试图测试每个方法/属性的行为是否符合预期,而是我们想测试每个暴露的行为是否按预期工作.


作为替代方案,假设我们选择选项1并使用私人反射来检查_components我们自己的状态.在这种情况下,我们实际测试的bevahour是:

  • 如果我使用AddComponent,则应添加添加的组件_components
  • 如果我使用索引器,我应该能够访问任何组件 _components

我们现在不仅测试类的内部行为(因此,如果实现更改测试失败,即使类按预期工作),但我们只是我们编写的测试数量增加一倍.

最重要的是,通过增加测试的复杂性,我们增加了测试本身存在错误的可能性- 例如,如果我们犯了错误并且在测试2中,我们检查了一些完全不同的私有字段?在这种情况下,我们不仅为自己做了更多工作,而且我们甚至没有测试我们想要测试的实际行为!