【问题标题】:Unit test complex classes with many private methods使用许多私有方法对复杂类进行单元测试
【发布时间】:2010-04-29 15:33:21
【问题描述】:

我有一个具有一个公共方法和许多私有方法的类,这些方法的运行取决于传递给公共方法的参数,因此我的代码如下所示:

public class SomeComplexClass
{
    IRepository _repository;

    public SomeComplexClass()
       this(new Repository())
    {
    }

    public SomeComplexClass(IRepository repository)
    {
        _repository = repository;
    }


    public List<int> SomeComplexCalcualation(int option)
    {
        var list = new List<int>();

        if (option == 1)
            list = CalculateOptionOne();
        else if (option == 2)
            list = CalculateOptionTwo();
        else if (option == 3)
            list = CalculateOptionThree();
        else if (option == 4)
            list = CalculateOptionFour();
        else if (option == 5)
            list = CalculateOptionFive();

        return list;
    }

    private List<int> CalculateOptionOne()
    {
        // Some calculation
    }

    private List<int> CalculateOptionTwo()
    {
        // Some calculation
    }

    private List<int> CalculateOptionThree()
    {
        // Some calculation
    }

    private List<int> CalculateOptionFour()
    {
        // Some calculation
    }

    private List<int> CalculateOptionFive()
    {
        // Some calculation
    }
}

我想了几种方法来测试这个类,但它们似乎都过于复杂,或者暴露的方法比我想要的要多。到目前为止的选项是:

  • 将所有私有方法设置为 internal 并使用 [assembly: InternalsVisibleTo()]

  • 将所有私有方法分离成一个单独的类并创建一个接口。

  • 将所有方法设为虚拟,并在我的测试中创建一个继承自此类的新类并覆盖这些方法。

是否有任何其他选项可以测试上述课程,这会比我列出的更好?

如果你会选择我列出的其中一个,你能解释一下原因吗?

谢谢

【问题讨论】:

  • 这与您的问题无关,但 if/else 结构让我觉得很奇怪。从设计的角度来看,您是否经常让该类的客户端调用多种类型的计算,或者单个客户端通常只调用一个选项?
  • 这是我实际课程的简化版本,但许多客户通常会调用很多选项。

标签: unit-testing testing dependency-injection mocking separation-of-concerns


【解决方案1】:

您无需更改界面即可测试这些方法。只需彻底测试公共接口以确保测试所有私有方法:

 void Test1() 
 {
      new SomeComplexClass(foo).SomeComplexCalcualation(1);
 } 

 void Test2() 
 {
      new SomeComplexClass(foo).SomeComplexCalcualation(2);
 } 

等等……

您可以使用覆盖率工具(例如,NCover 用于 .NET)来确保您想要测试的所有代码都经过实际测试。

【讨论】:

    【解决方案2】:

    OptionCalculators 怎么样,原来的类将工作分派给它?每个都只有一个方法,CalculateOption,当然它是公开的,因此很容易测试。

    【讨论】:

    • 优雅的方法。一个接口,多个小实现。然后只需遍历接口列表并调用公共方法。
    【解决方案3】:

    您应该只需要测试类/接口的公共方法。

    您只需要确保您有足够的单元测试用例来彻底测试这些公共方法的所有不同行为(这将适当地锻炼私有方法)。

    【讨论】:

      【解决方案4】:

      如果这些计算中的每一个都那么复杂,那么每一个真的是一个单一的方法吗?如果这些计算共享代码,或者每个应该是多个方法,那么这是您提到的接口/策略方法的参数,因此您可以测试每个步骤。

      另一件要考虑的事情:彻底使用一个公共方法是测试两件事 a) ComputeOptionN 代码正在运行,并且 b) 选项检查工作正常。

      如果您实际上是在传递整数,这不是问题,但不是理想的,特别是如果比较可能会变得更加复杂,或者它可能会改变。

      【讨论】:

        【解决方案5】:

        @Carl 是对的。这无非是利用一种策略模式。将所有calculators 存储在一个数组中,将该数组注入SomeComplexClass。这将允许您单独对每个calculatorSomeComplexClass 进行单元测试。现在你可以这样做了:

        public List<int> SomeComplexCalcualation(int option)
        {
             return calculator.find(option);
        }
        

        很容易模拟calculator

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2022-11-30
          • 1970-01-01
          • 2010-09-20
          • 2018-06-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多