单元测试、私有方法和隐藏抽象
Unit tests, private methods and hidden abstraction
我正在阅读有关单元测试的内容,以了解更多相关信息。
似乎测试私有方法不应该是一般规则,只是一些例外。我找到了这篇文章,其中解释说:https://enterprisecraftsmanship.com/posts/unit-testing-private-methods/
这里说如果私有方法比较复杂,一个办法是创建一个publicclass然后实现这里的方法,这样就可以测试了。
这是我的疑问。
不测试私有方法的原因是因为建议只测试客户端可以从库中使用的内容。
使用私有方法的原因是不让客户知道或了解内部实现的详细信息,因此最好让客户的库尽可能简单。
但是,如果为了测试私有方法,我创建了一个新的 public class 将方法放在那里,现在 public,我是否没有向客户提供有关实现的详细信息?实际上,不是声明 public 私有方法,而是创建一个 public class 来放置 public 方法。
所以我想我误会了什么,但我不知道是什么。
在这个问题的一个答案中:How do you unit test private methods? 据说一种选择是将私有方法也传递给 public class,但它没有不解释了(我想答案可能会更长)。
谢谢。
But if for test the private method I create a new public class put the method there, now public, am I not giving to the client details about the implementation?
这里的诀窍是不要实际上暴露它。具体如何做到这一点取决于 language/ecosystem,但一般来说,您将尝试以最终用户无法(轻松)访问实现细节的方式发布代码。
例如,在 C++ 中,您可以使用 private headers 公开您的库中未附带的功能(如果它们不包含在您的界面中就没有问题 headers) . Java 有它的“拼图”模块系统。但即便如此,如果不能机械强制执行,你仍然可以社会强制执行它,方法是通过包装和class 最终用户不应该使用的东西的名称;例如,如果您不使用 Java 的模块系统,您仍然可以在名为 lib.foo.implementation_details
的包中获得包 lib.foo
的实现细节,类似于 Smalltalk 等语言在你根本没有私有方法的地方,你仍然可以给你的方法命名,比如 private_foo
,这很清楚它们不适合外部用户使用。
当然,机械执法更好,但正如您所注意到的,这并不总是一种选择。即使它不可用,私有与 public 和接口与实现的 原则 仍然适用,您只需要在如何确保人们其实坚持这些东西。
The reason to don't test private methods it is because it is recomended to test only what the client can use from the library.
有很多人解释 "the" 单元测试的目标,但实际上他们在描述 他们 进行单元测试时的目标。单元测试应用于许多不同的领域和环境,从玩具项目开始,到核电站、飞机等与安全相关的软件结束。
也就是说,有很多开发的软件,上面的推荐可能都还好。但是,您可以应用除此之外的单元测试方式。如果您不想从对单元测试的内容有限制的观点开始,您最好按以下方式查看它:一般测试和单元测试的主要目标之一是找到错误(参见 Myers、Badgett、Sandler:软件测试的艺术,或 Beizer:软件测试技术,还有许多其他内容)。
想当然地认为单元测试就是找Bug,那么你可能还想测试实现细节:Bug在实现中——相同功能的不同实现有不同的Bug。以一个简单的斐波那契函数为例:它可以实现为递归函数、迭代函数、闭合表达式(Moivre/Binet),使用手写查找-table,使用自动生成的lookup-table 等。对于这些实现中的每一个,可能出现的错误集将大不相同。
另一个例子是排序:有大量的排序函数,从功能的角度来看,它们做同样的事情,许多甚至具有相同的用户界面。 IntroSort 算法在测试方面非常有趣,因为它实现了快速排序,但当它意识到它遇到退化排序时,它会回退到另一种算法(通常是堆排序)。测试 IntroSort 意味着,还创建这样一个退化的数据集,迫使算法进入堆排序,只是为了确保可以找到堆排序部分中的潜在错误。单看public接口,你绝对不会想出这样的测试用例(至少那是相当巧合)。
到目前为止总结:测试实现细节绝不是坏习惯。这是有代价的:当实现发生变化时,进入实现细节的测试肯定更有可能被破坏或变得无用。因此,是否发现更多错误比节省测试维护工作量更重要,取决于您的项目。
关于使私有函数可用于测试但仍不使它们成为 "official" public 接口的一部分的可能性:@Cubic 很好地解释了 a) 与 public
在给定编程语言的可见性规则的技术意义上,和 b) 属于 "official" 并记录在案 public API.
我正在阅读有关单元测试的内容,以了解更多相关信息。
似乎测试私有方法不应该是一般规则,只是一些例外。我找到了这篇文章,其中解释说:https://enterprisecraftsmanship.com/posts/unit-testing-private-methods/
这里说如果私有方法比较复杂,一个办法是创建一个publicclass然后实现这里的方法,这样就可以测试了。
这是我的疑问。
不测试私有方法的原因是因为建议只测试客户端可以从库中使用的内容。
使用私有方法的原因是不让客户知道或了解内部实现的详细信息,因此最好让客户的库尽可能简单。
但是,如果为了测试私有方法,我创建了一个新的 public class 将方法放在那里,现在 public,我是否没有向客户提供有关实现的详细信息?实际上,不是声明 public 私有方法,而是创建一个 public class 来放置 public 方法。
所以我想我误会了什么,但我不知道是什么。
在这个问题的一个答案中:How do you unit test private methods? 据说一种选择是将私有方法也传递给 public class,但它没有不解释了(我想答案可能会更长)。
谢谢。
But if for test the private method I create a new public class put the method there, now public, am I not giving to the client details about the implementation?
这里的诀窍是不要实际上暴露它。具体如何做到这一点取决于 language/ecosystem,但一般来说,您将尝试以最终用户无法(轻松)访问实现细节的方式发布代码。
例如,在 C++ 中,您可以使用 private headers 公开您的库中未附带的功能(如果它们不包含在您的界面中就没有问题 headers) . Java 有它的“拼图”模块系统。但即便如此,如果不能机械强制执行,你仍然可以社会强制执行它,方法是通过包装和class 最终用户不应该使用的东西的名称;例如,如果您不使用 Java 的模块系统,您仍然可以在名为 lib.foo.implementation_details
的包中获得包 lib.foo
的实现细节,类似于 Smalltalk 等语言在你根本没有私有方法的地方,你仍然可以给你的方法命名,比如 private_foo
,这很清楚它们不适合外部用户使用。
当然,机械执法更好,但正如您所注意到的,这并不总是一种选择。即使它不可用,私有与 public 和接口与实现的 原则 仍然适用,您只需要在如何确保人们其实坚持这些东西。
The reason to don't test private methods it is because it is recomended to test only what the client can use from the library.
有很多人解释 "the" 单元测试的目标,但实际上他们在描述 他们 进行单元测试时的目标。单元测试应用于许多不同的领域和环境,从玩具项目开始,到核电站、飞机等与安全相关的软件结束。
也就是说,有很多开发的软件,上面的推荐可能都还好。但是,您可以应用除此之外的单元测试方式。如果您不想从对单元测试的内容有限制的观点开始,您最好按以下方式查看它:一般测试和单元测试的主要目标之一是找到错误(参见 Myers、Badgett、Sandler:软件测试的艺术,或 Beizer:软件测试技术,还有许多其他内容)。
想当然地认为单元测试就是找Bug,那么你可能还想测试实现细节:Bug在实现中——相同功能的不同实现有不同的Bug。以一个简单的斐波那契函数为例:它可以实现为递归函数、迭代函数、闭合表达式(Moivre/Binet),使用手写查找-table,使用自动生成的lookup-table 等。对于这些实现中的每一个,可能出现的错误集将大不相同。
另一个例子是排序:有大量的排序函数,从功能的角度来看,它们做同样的事情,许多甚至具有相同的用户界面。 IntroSort 算法在测试方面非常有趣,因为它实现了快速排序,但当它意识到它遇到退化排序时,它会回退到另一种算法(通常是堆排序)。测试 IntroSort 意味着,还创建这样一个退化的数据集,迫使算法进入堆排序,只是为了确保可以找到堆排序部分中的潜在错误。单看public接口,你绝对不会想出这样的测试用例(至少那是相当巧合)。
到目前为止总结:测试实现细节绝不是坏习惯。这是有代价的:当实现发生变化时,进入实现细节的测试肯定更有可能被破坏或变得无用。因此,是否发现更多错误比节省测试维护工作量更重要,取决于您的项目。
关于使私有函数可用于测试但仍不使它们成为 "official" public 接口的一部分的可能性:@Cubic 很好地解释了 a) 与 public
在给定编程语言的可见性规则的技术意义上,和 b) 属于 "official" 并记录在案 public API.