主持人注:这里已经有39个答案了(有些已经删除了)。在你发表你的答案之前,考虑一下你是否可以为讨论添加一些有意义的东西。你很可能只是在重复别人已经说过的话。


我偶尔发现自己需要将类中的私有方法设为public,只是为了为它编写一些单元测试。

通常这是因为该方法包含类中其他方法之间共享的逻辑,并且单独测试逻辑更整洁,或者另一个原因可能是我想测试同步线程中使用的逻辑,而不必担心线程问题。

其他人发现他们这样做是因为我不喜欢吗?我个人认为,公开一个方法的好处超过了它在类之外没有提供任何服务的问题……

更新

谢谢大家的回答,似乎引起了大家的兴趣。我认为普遍的共识是测试应该通过公共API进行,因为这是使用类的唯一方式,我非常同意这一点。在我上面提到的几个案例中,我会这样做,这是不常见的情况,我认为这样做的好处是值得的。

然而,我可以看到,每个人都指出它不应该真的发生。再仔细想想,我觉得改变你的代码来适应测试是一个坏主意——毕竟我认为测试在某种程度上是一个支持工具,而改变一个系统来“支持一个支持工具”是明显的坏做法。


当前回答

You should never ever ever let your tests dictate your code. I'm not speaking about TDD or other DDs I mean, exactly what your asking. Does your app need those methods to be public. If it does then test them. If it does not then then don't make them public just for testing. Same with variables and others. Let your application's needs dictate the code, and let your tests test that the need is met. (Again I don't mean testing first or not I mean changing a classes structure to meet a testing goal).

相反,你应该“考高一点”。测试调用私有方法的方法。但是您的测试应该测试您的应用程序需求,而不是您的“实现决策”。

例如(此处为bod伪代码);

   public int books(int a) {
     return add(a, 2);
   }
   private int add(int a, int b) {
     return a+b;
   } 

没有理由测试“add”,你可以测试“books”。

永远不要让你的测试为你做代码设计决策。测试你是否得到了预期的结果,而不是你如何得到结果。

其他回答

最近,当重构一个大方法(> 200行)时,我也有同样的想法。对于每个逻辑步骤,我成功地将大方法拆分为较小的方法,因此很容易进行推理。

当涉及到重构出来的小型私有方法时,我想知道我是否应该单独测试它们,因为如果我只测试公共方法,我仍然在测试大方法,测试根本没有从重构中受益

经过一番思考,我意识到:

if all the small methods are private and can't be reused by others, maybe I am doing something wrong: I am not pulling the right abstraction from the code, I am only splitting the big methods treating them like lines/strings, not like mental barrier when I came to the right small methods(I refactored again, completely changing the small methods), and move the small methods into another class exposed as public methods for others to use, now I can test them(and I should test them, they will be used more and deserver the attention)

简介:

我仍然有很多小的私有方法,但是它们共享了很多公共方法,而且小方法真的很小(3-4行,主要是函数调用),但我不会测试它们,我只需要在另一个类中测试共享的公共方法

在. net中,有一个叫做PrivateObject的特殊类,专门用于允许您访问类的私有方法。

在MSDN或Stack Overflow上查看更多信息

(我很奇怪,到目前为止还没有人提到它。)

但在某些情况下,这是不够的,在这种情况下,你必须使用反射。

尽管如此,我还是会坚持不测试私有方法的一般建议,然而,像往常一样,总会有例外。

正如其他人所说,单元测试私有方法有点可疑;单元测试公共接口,而不是私有实现细节。

也就是说,当我想对c#中私有的东西进行单元测试时,我使用的技术是将可访问性保护从私有降级为内部,然后使用InternalsVisibleTo将单元测试程序集标记为友程序集。然后,单元测试程序集将被允许将内部组件视为公共的,但您不必担心会意外地增加公共表面区域。

更新:我已经在其他很多地方对这个问题增加了一个更广泛、更完整的答案。这可以在我的博客上找到。

如果我需要公开一些东西来测试它,这通常暗示被测试的系统没有遵循单一责任原则。因此,应该引入一个缺失的类。将代码提取到一个新类后,将其设为public。现在您可以轻松地进行测试,并且遵循SRP。您的其他类只需通过组合调用这个新类。

使方法公开/使用语言技巧,例如将代码标记为对测试程序集可见,应该始终是最后的手段。

例如:

public class SystemUnderTest
{
   public void DoStuff()
   {
      // Blah
      // Call Validate()
   }

   private void Validate()
   {
      // Several lines of complex code...
   }
}

通过引入验证器对象重构此对象。

public class SystemUnderTest
{
    public void DoStuff()
    {
       // Blah
       validator.Invoke(..)
    }
}

现在我们要做的就是测试验证器是否被正确调用。验证的实际过程(以前的私有逻辑)可以在完全隔离的情况下进行测试。不需要复杂的测试设置来确保验证通过。

我想说这是一个坏主意,因为我不确定你是否会得到任何好处,并可能出现问题。如果你改变一个调用的契约,只是为了测试一个私有方法,你并不是在测试这个类将如何使用它,而是在创建一个你从未打算发生的人为场景。

此外,通过将方法声明为公共,在六个月的时间内(在忘记将方法公开的唯一原因是为了测试之后),您(或者如果您已经移交了项目)完全不同的人将不会使用它,从而导致潜在的意想不到的后果和/或维护噩梦。