【问题标题】:Unit testing an alias method单元测试别名方法
【发布时间】:2015-01-31 04:20:25
【问题描述】:

对只调用 2 个其他方法且没有逻辑的方法进行单元测试的最佳做法是什么?

internal ICollection<ObjA> FunctionA()
{
    IEnumerable<ObjB> b = _factory.FunctionB();
    return FunctionC(b);
}

_factory.FunctionB()FunctionC(b) 都有针对它的单元测试,所以如果这些方法坏了我们就会知道。

我正在考虑伪造这两个函数,并且只进行一个单元测试以确保从FunctionA() 调用这些方法。但是如果FunctionB()FunctionC() 发生变化,FunctionA() 可能会变成误报。

【问题讨论】:

  • 模拟出这两个功能,正如你提到的。如果任何一个模拟函数发生变化,这不是误报;看到 functionA 调用这两个函数是正确的测试。这两个模拟函数的测试正确地包含在其他测试中。
  • 我认为这是 C#?

标签: c# unit-testing


【解决方案1】:

我倾向于不对私有或内部方法进行单元测试,因为它们应该在对公共 API 进行单元测试时执行。

假设这是一个公共方法,我将根据私有成员 _factory 的状态进行测试,检查您在调用 FunctionA() 时期望的返回值。假设您可以控制 _factory 的输出(通过它是可模拟的接口、可子类化的基类,或者只是用已知值简单实例化并传递给类的构造函数),您可以确保获得预期的输出基于该初始输入的 FunctionA。

如果您发现每次更新 FunctionB 或 FunctionC 时都会收到误报,我会质疑为什么 FunctionA 存在。更有可能的情况是,在 FunctionA 上中断的单元测试将导致您更改 FunctionA 的内部实现,因为对 FunctionB 和 FunctionC 的更改不再使它们成为 FunctionA 的合适实现,或者它们会导致您为这些函数来修复 FunctionA 中的间接损坏。

在这个特定示例中,FunctionA 似乎只是一个包装器,用于将 ObjB 转换为 ObjA,其数据源已由内部工厂类指定。对于这个特定的场景,我将为 FunctionA 设置测试,以便如果上层需求发生变化(因为实施了关于如何将 ObjB 转换为 ObjA 的新规则),以便我可以将新逻辑放在 FunctionA 或 FunctionC 中,具体取决于哪个我觉得比较合适。

例子:

internal ICollection<ObjA> FunctionA()
{
    IEnumerable<ObjB> b = _factory.FunctionB();
    // in the future unit test may drive that a different implemetation is used 
    // based on some data about b.
    if(b.SomeCondition())
        return FunctionC(b);
    else
        return FunctionD(b);
}

或者可能是 C 需要改变

internal ICollection<ObjA> FunctionC(IEnumerable<ObjB> objBEnumerable)
{
    ICollection<ObjA> objACollection = initializeCollection();
    foreach(var objB in objBEnumerable)
    {
        //updated logic to create objA from objB goes here
        objACollection.Add(createdObjA);
    }
    return objACollection;
}

基本上,您的问题的答案是“视情况而定”,但如果函数 B 和 C 的覆盖率已经很好,以防 A 需要在第一个代码示例中转移未来。

【讨论】:

  • 如果您不测试私有或内部方法,如果这些方法嵌套在几个抽象级别中,您的测试用例会不会变得更复杂?您必须为所有依赖项设置数据。假设 FunctionA 返回值大于 10 的 obj,FunctionB 返回值大于 3 的 obj。如果您对 FunctionB 进行了更改,并且在单元测试中模拟了 FunctionB,导致 FunctionA 单元测试仍然通过,那不能结束吗是误报?
  • 不是我不测试它们,而是我通过公共API间接测试它们(这些方法是调用函数的方法)。我可能不会模拟函数 B(_factory 将是实时实现,而不是模拟),而 FuncitonA 现在在这种情况下会失败。这个失败的测试现在可以引导您思考 FunctionB 和 A 应该如何相互交互的过程。抽象地讲这个有点困难,所以我今晚回家时会用更具体的东西来更新我的答案。
  • 但是,如果您不测试被模拟对象的所有潜在场景,模拟内部对象可能会导致误报。因此,理想情况下,您应该有 FunctionA 测试来检查 FunctionB 的许多不同返回值。
  • 更多关于不直接对私有方法进行单元测试的哲学信息:stackoverflow.com/questions/5601730/…
  • 内部 私有。通常 internal 用于需要进行单元测试但也会暴露给程序集的所有用户的类。使用 internal 您可以使用 InternalsVisibleTo 将它们公开给单元测试项目,并且仍然将它们保留为程序集的实现细节。比必须从公共 API 中“集成测试”这些类要好得多。内部方法顺便说一句,我不“明白”:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多