1

我已经查看了有关该主题的其他讨论(在 StackOverflow 上),但是其他问题似乎是特定于语言的,而这不是特定于语言的,我正在考虑不再使用私有方法、类和模块。

我想测试我的私有方法、类和模块,以便更容易找到错误。为了允许我这样做,我正在考虑不再使用私有方法、类和模块,原因有两个:(1)我认为没有任何合理的方法可以在不注入测试代码或使用某种类型的情况下测试私有方法、类或模块的“魔术”和(2)提高代码重用。请注意,我不考虑不再使用私有变量和属性,因为数据需要保护并且不提供行为,因此它不需要在测试期间公开。

作为一个蹩脚的例子,如果你正在编写一个名为的模块OneOperations,它有两个公共方法addOneandsubtractOne和两个私有方法addand subtract。如果您不允许自己拥有私有方法,您可以将这两个私有方法放入另一个模块(basicOperations)中,它们是公共的,并在OneOperations模块中导入这些方法。从此,您现在应该能够为两个模块中的所有方法编写测试代码,而无需注入代码。这样做的一个优点是方法addsubtract现在可以通过导入basicOperations模块在其他模块中使用(2 - 改进代码重用)。

我觉得这是个坏主意,但我缺乏现实世界的经验来证明不这样做是合理的,这就是我在 StackOverflow 上发布这个问题的原因。

那么,你如何测试你的私有方法、类和模块呢?编写私有方法、模块和类不是一个潜在的解决方案吗?

4

2 回答 2

1

1)就像这个主题的许多其他答案一样,主要问题是你为什么要测试你的私有方法?类的目的是为其客户提供一些功能。如果你有全面的单元测试证明这个类的公共接口行为正确,你为什么要关心它在私有方法中的作用呢?

2)您根本没有私有方法的想法似乎就像断了腿一样。对于小型项目,可以很好地分离和测试每一个微小的行为。但是对于大型项目来说,这是一种矫枉过正的做法。重要的是域逻辑的行为是否正确。

例如考虑一个方法:

public double getDistanceSquared(Point other)
{
    return getDifferenceSquared(this.x, other.x)
      + getDifferenceSquared(this.y, other.y); 
}

private double getDifferenceSquared(double v1, double v2)
{
    return (v1 - v2)*(v1 - v2);
}

Ad1) 如果对所有测试用例返回正确的结果,单元测试getDifferenceSquared方法真的有意义吗?getDistanceSquared

Ad2)创建一个单独的类来计算双打之间的平方距离 - 如果只有一个地方使用它会导致一大群小类,数百万次测试。此外,域类的构造函数将接受 10 个不同的接口,用于他们在内部做的每一件小事。

维护这一切是很多不必要的工作。想象一下,您想更改计算距离的方法(可能使用一些预先计算的值)。的行为getDistanceSquared不会改变。但是您必须更改所有测试,getDifferenceSquared即使您不必关心如何计算距离,只要计算正确即可。

在不必要的时候深入细节会让你忘记你真正在做什么——你失去了“大局观”。珍惜你的时间,专注于重要的问题。

作为旁注,单元测试的主要关注点不是您建议的“定位错误”。它们采用简洁的设计,提供始终最新的代码行为文档,并允许方便的重构,从而为您提供灵活性。此外,他们向您保证代码按您期望的那样工作。

http://artofunittesting.com/definition-of-a-unit-test/

http://en.wikipedia.org/wiki/Unit_testing#Benefits

于 2013-09-22T11:42:56.733 回答
1

还有另一种看待这个的方法,即如何生成私有方法?

如果我们正确地遵循了 TDD 流程,那么我们编写的第一件事就是测试。此时测试应该包含我们所有的代码,例如

public void ShouldAddTwoNumbers()
{
  (1 + 1).ShouldEqual(2);
}

是的,这看起来很骇人听闻。但是考虑一下在我们编写时发生的事情是一些更多的测试。

public void ShouldAddTwoMoreNumbers()
{
  (2 + 2).ShouldEqual(4);
}

现在我们有一些东西要反应,所以它可以变成

public void ShouldAddTwoNumbers()
{
  Add(1, 1).ShouldEqual(2);
}

public void ShouldAddTwoMoreNumbers()
{
  Add(2, 2).ShouldEqual(4);
}

private int Add(int a, int b)
{
  return a+b;
}

所以现在我们有一个私有方法,我们可以在我们的测试类中进行测试。只有当您完成进一步的重构以将代码移到您的应用程序中时,私有才会成为问题。大多数自动重构工具会在此时为您提供更改方法签名的选项,以便私有方法仍然可以访问,因为它不是私有的。

(有一个很棒的练习叫做TDD,好像你的意思是 Keith Braithwaite 的意思,我刚刚在上面解释过)

然而,这并不是我们重构和开发的结束。我们在编写和重构测试时应该做的一件事是删除旧的测试,例如当功能重复时。另一个是提取新方法,这样我们就不会重复自己。这两种情况都可能导致我们在非测试代码库中拥有私有方法。

所以我的建议是务实,为你面前的代码做出最好的决定。我不建议不要创建私有方法,但我会关注导致您创建它们的因素。

于 2013-10-02T00:04:58.573 回答