如何测试私有函数或具有私有方法,字段或内部类的类?

MattGrommes 2593 java tdd unit-testing

如何对具有内部私有方法,字段或嵌套类的类进行单元测试(使用xUnit)?或者通过内部链接(static在C/C++中)或在私有(匿名)命名空间中使其成为私有的函数?

为了能够运行测试而更改方法或函数的访问修饰符似乎很糟糕.

Cem Catikkas.. 1572

如果您有一些遗留Java应用程序,并且不允许更改方法的可见性,那么测试私有方法的最佳方法是使用反射.

在内部,我们使用帮助器来获取/设置@Jailbreakprivate变量以及调用private staticprivate方法.以下模式将允许您执行与私有方法和字段相关的任何操作.当然,你private static不能通过反射来改变变量.

@Jailbreak Foo foo = new Foo();
// Direct, *type-safe* access to *all* foo's members
foo.privateMethod(x, y, z);
foo.privateField = value;

对于领域:

Method method = TargetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);

注意:
1.private static final让你看看TargetClass.getDeclaredMethod(methodName, argClasses)方法.同样的事情也适用 private.
2. getDeclaredField需要与私人一起玩耍.

  • 如果您不熟悉API,则很有用,但如果您必须以这种方式测试私有方法,那么您的设计就会出现问题.正如另一张海报所说,单元测试应该测试类的合同:如果合同太宽泛并且实例化了太多的系统,那么应该解决设计问题. (327认同)
  • 比直接使用反射更好的是使用一些库,例如[Powermock](http://code.google.com/p/powermock/wiki/BypassEncapsulation). (34认同)
  • 这就是测试驱动设计有用的原因.它可以帮助您确定需要暴露的内容以验证行为. (22认同)
  • 很有用.使用此功能时,请务必记住,如果在混淆后运行测试,则会严重失败. (20认同)
  • 示例代码对我不起作用,但这使得更清晰:http://www.java2s.com/Tutorial/Java/0125__Reflection/Callaclassmethodwith2arguments.htm (18认同)
  • 大多数纯粹主义者都没有承认存在合法的案例.我的情况:我正在为(闭源)商业产品编写插件.为*public*方法编写常规单元测试涉及模拟该产品的大部分内容,并且这种方法存在限制.能够以上述方式测试我的*private*方法可确保我的代码在部署之前已经过95%的测试. (6认同)
  • 很遗憾看到这样一个非常错误的答案会得到如此多的赞成.应该*不*减少方法或字段的可访问性,也不应通过Reflection访问它们.多年来,我已经写了数千个JUnit/TestNG,而且我从不*不得不直接测试`private`方法.偶尔,我必须阅读一个`private`字段(通过Reflection),但那是关于它的.我猜一些开发人员(很多人,显然)懒得编写正确的测试(只调用`public`方法),而更喜欢使用Reflection作弊. (5认同)
  • 遗留与否,您不应为了测试目的而更改可见性.在任何情况下+1都反映. (4认同)
  • 不,我不认为对TDD的吸引力是一种有效的批评.为什么要将涵盖私有方法的单元测试从该封装中排除?如果TDD应该告诉你公开这个方法,那么你不是在这里制作高质量的代码,而是在语言本身中弥补逻辑上的缺陷. (3认同)
  • 测试私有方法应该由公共成员完成,不由公共成员直接或间接调用的私有成员没有价值.单元测试和TDD不是直接测试所编写的每个方法,而是与编写该代码的要求相比,测试编写代码的行为. (3认同)
  • 真的......任何反思都会在混淆之后惨败. (2认同)
  • 这一切都很棒(我已经做了很长时间了),但是有一个小问题,我试图找到解决方案.想象一下,你想测试私有方法的异常结果.例如,您将获得null Class:java.lang.reflect.InvocationTargetException,而不是给出IllegalArgumentException的方法调用.也许有办法覆盖这个,但我不熟悉它.我的一个colegue建议使用powermock. (2认同)
  • 不应该是getClass().getDeclaredMethod()? (2认同)

Trumpi.. 582

测试私有方法的最佳方法是通过另一种公共方法.如果无法执行此操作,则满足下列条件之一:

  1. 私有方法是死代码
  2. 您正在测试的课程附近有一种设计气味
  3. 您尝试测试的方法不应该是私有的

  • 不同意.在私有方法中使用算法是完全有效的,这需要比通过类的公共接口实现更多的单元测试. (1051认同)
  • @先生.有光泽和新颖:如果你的私有方法足够复杂以保证独立的单元测试,那么它就足够复杂以拥有自己的类.该课程当然可以是内部的(即无法从其他包中访问). (172认同)
  • @sleske,我不同意.你可以有一个小的私人方法,根据设计,你需要它是私人的.我宁愿测试每一小段代码,也不愿通过公共方法测试私有方法.这种测试方式将进行组件测试. (90认同)
  • 嘿Shiny先生是的,但是那时你会进行脆弱的测试.另外,请参阅我的回复中的第2个. (67认同)
  • 脆弱的测试是一种测试,当代码发生变化时,测试很容易失败.通常,当测试结果基于方法的作用而不是预期的输出和给定一组输入的副作用时,就会发生这种情况.理想情况下,对代码的更改不会改变结果不应该破坏测试. (55认同)
  • @Pete我同意.我的团队测试私有方法,我觉得我浪费了大量时间"修复"私有方法的单元测试,这些方法在我改变类的私有内部工作方式后开始失败,而不改变类的合同.我看看失败的测试,它现在失败了,因为私有方法f没有被调用3次,或者私有方法g返回了一些不同的结果.然而,公开测试并未破裂.对我来说这是一种浪费,对于那些测试来说并不是很有帮助.调试器上的2秒将显示一些公共方法失败的地方... (35认同)
  • @grinch现货.测试私有方法唯一可以获得的是调试信息,这就是调试器的用途.如果您对班级合同的测试完全覆盖,那么您将获得所需的所有信息.私有方法是**实现**细节.如果您对它们进行测试,则每次实施更改时都必须更改测试,即使合同没有.在软件的整个生命周期中,这可能比它给出的好处花费更多. (25认同)
  • 几乎所有私人方法都不应该直接测试(以降低维护成本).例外:科学方法可能有f(a(b(c(x),d(y))),a(e(x,z)),b(f(x,y,z),z)等形式其中a,b,c,d,e和f是非常复杂的表达式,但在这个单一公式之外是无用的.一些函数(想想MD5)难以反转,因此选择完全覆盖行为空间的参数可能很困难(NP-Hard).更容易独立地测试a,b,c,d,e,f.将它们公开或封装私有谎言它们是可重用的.解决方案:将它们设为私有,但要测试它们. (14认同)
  • 测试 - 私有方法阵营忽略了这一点:测试私有方法可能需要花费大量的工作和时间,而且当测试失败时,它不可能节省任何/足够的时间.如果测试因NPE等私有方法中的某些错误而失败,您仍然可以直接解决问题(私有方法).如果私有方法生成的数据不匹配,则可以通过调试equals()在断言中轻松查看.在某些情况下,使用反射编写数十个私有方法测试可能是有意义的,但需要清楚可见. (13认同)
  • 但是,内部类是不是会增加更复杂的东西,这些东西可能很难理解,但是为了避免重复而将4行代码提取到私有方法中? (11认同)
  • 进行更细粒度的测试,涵盖较小的私有方法意味着当事情确实破坏时,您的测试将告诉您在哪里.毕竟,编码输入和输出是/假设/,我们测试这些假设仍然是正确的.如果您的内部"脆弱"测试中断,那么关于它如何工作的假设已经改变,并且使用它的代码可能会以微妙的方式被破坏. (9认同)
  • 我不明白为什么测试私有方法会产生代码味道?单元测试的重点不是测试每个小部件以隔离错误.你能解释一下脆弱的测试吗? (8认同)
  • @AlexWien你是对的.覆盖范围不是正确的术语.我应该说的是"如果你对班级合同的测试涵盖了所有有意义的输入和所有有意义的状态".您正确地指出,这可能证明通过公共接口测试代码是不可行的,或者在您引用它时间接测试.如果您正在测试的某些代码就是这种情况,我倾向于认为:(1)合同过于慷慨(例如方法中的参数太多),或者(2)合同太模糊(例如方法行为)与班级国家有很大差异).我会考虑两种设计气味. (8认同)
  • 此外,我们永远不会接近100%的代码覆盖率,所以为什么不把时间集中在客户实际将直接使用的方法上进行质量测试. (6认同)
  • @Eponymous我对这个有点不知所措.在我看来,面向对象的纯粹主义者会说你应该使用面向对象的方法而不是静态私有方法,允许你通过公共实例方法进行测试.但话说回来,在科学框架中,内存开销完全可能是我认为静态方法所引发的问题. (4认同)
  • (通常,当测试开始失败时,您将找到调试器以找出原因,通过较小的子测试可以更快地找到故障发生的位置) (3认同)
  • @ErikMadsen完全覆盖并不意味着正确的结果.直接单元测试可以检查正确的结果.间接经常不是. (2认同)
  • 第三种方法是暂时将复杂的私有方法公开,但仅限于初始实施期间,以便在不改变设计的情况下轻松测试它们.然后,当类已经发展到可以从公共API可靠地测试时,请将该方法设为私有,并将测试用例集中在公共API上.这允许您在不破坏测试的情况下更改实现,并在私有方法破坏任何内容时仍然提醒您.我只对复杂的私有方法这样做,即使这样,以某种方式拆分它们可能更有意义. (2认同)
  • @ErikMadsen我在考虑实例方法.我的观点是,有些方法非常复杂,无法通过测试组件来发现错误.但是,这些组件是实现细节.打破它们会使设计变得混乱,从而降低了软件的可读性. (2认同)

Jay Bazuzi.. 302

当我在一个足够复杂的类中使用私有方法时,我觉得需要直接测试私有方法,这就是代码味道:我的类太复杂了.

我解决此类问题的常用方法是梳理出一个包含有趣内容的新类.通常,此方法及其与之交互的字段以及可能的另一种方法可以被提取到新类中.

新类将这些方法公开为"公共",因此它们可以进行单元测试.新旧课程现在都比原来的课程简单,这对我来说很棒(我需要保持简单,否则我会迷路!).

请注意,我并不是说人们在不使用大脑的情况下创建课程!这里的要点是使用单元测试的力量来帮助您找到好的新类.

  • 问题是如何测试私有方法.你说你会为此做新的课程(并增加更多的复杂性)并建议不要创建新课程.那么如何测试私有方法呢? (23认同)
  • @Dainius:我不建议单独创建一个新类*,以便您可以测试该方法.我建议编写测试可以帮助您改进设计:好的设计很容易测试. (22认同)
  • 但是你同意好的OOD会暴露(公开)只有那个类/对象正常工作所必需的方法吗?所有其他应该是私人/ protectec.因此在一些私有方法中会有一些逻辑,IMO测试这些方法只会提高软件的质量.当然我同意,如果某些代码是复杂的,它应该分成单独的方法/类. (13认同)
  • @Danius:在大多数情况下,添加新类会降低复杂性.只是测量它.在某些情况下,可测试性与OOD作斗争.现代方法有利于可测试性. (6认同)
  • 我认为,如果你有方法,就不需要创建另一个类只是为了能够测试该方法.我不认为类设计在这里有问题.所以我假设作者之前做了所有事情以便进行适当的设计,因此为一种方法引入另一个类只会增加复杂性.当然,当你有足够复杂的程序时,就没有明显的错误.. (4认同)
  • 这正是*如何使用测试反馈来驱动和改进您的设计!听听你的测试.如果他们很难写,那就告诉你一些关于你的代码的重要事情! (4认同)
  • @Charles但当然所有私有方法都已通过公共方法进行测试.该陈述应为"足够复杂,我认为需要单独测试****". (3认同)
  • 这里有一点鸡蛋问题.严格来说,您应该首先要在测试中重构代码,但是要测试首先需要将代码放在不同类中的代码.这对我来说似乎有点不理想. (2认同)
  • 对我来说,这篇文章的第一行非常具有启发性.如果算法太复杂并且值得测试以减少其他测试中的噪声,那么从现在开始,我将考虑_Strategy pattern_.考虑并不意味着使用,但绝对值得一看. (2认同)

Jon.. 270

我过去曾使用反射来为Java做这个,在我看来这是一个很大的错误.

严格来说,您应该编写直接测试私有方法的单元测试.您应该测试的是该类与其他对象的公共合同; 你永远不应该直接测试对象的内部.如果另一个开发人员想要对该类进行少量内部更改(这不会影响类公共合同),则他/她必须修改基于反射的测试以确保其有效.如果在整个项目中反复执行此操作,则单元测试将不再是对代码运行状况的有用度量,并开始成为开发的障碍,并对开发团队造成烦扰.

我建议改为使用Cobertura等代码覆盖工具,以确保您编写的单元测试在私有方法中提供良好的代码覆盖率.这样,您可以间接测试私有方法正在做什么,并保持更高的敏捷性.

  • +1给这个.在我看来,这是问题的最佳答案.通过测试私有方法,您正在测试实现.这违背了单元测试的目的,即测试类合同的输入/输出.测试应该*只*足够了解实现,以模拟它调用其依赖项的方法.而已.如果您无需更改测试就无法更改实施 - 可能是您的测试策略很差. (72认同)
  • @Colin M这不是他真正想要的;)让他来决定,你不知道这个项目. (10认同)

Iker Jimenez.. 204

从本文:使用JUnit和SuiteRunner(Bill Venners)测试私有方法,您基本上有4个选项:

  • 不要测试私有方法.
  • 给方法包访问权限.
  • 使用嵌套测试类.
  • 使用反射.


John Channin.. 120

通常,单元测试旨在运用类或单元的公共接口.因此,私有方法是您不希望显式测试的实现细节.

  • 这是IMO的最佳答案,或者通常说的是测试行为,而不是方法.单元测试不是源代码指标,静态代码分析工具和代码审查的替代品.如果私有方法如此复杂以至于需要分离测试,那么它可能需要重构,而不是更多的测试. (15认同)
  • 所以不要写私有方法,只需创建10个其他小类? (14认同)

Richard Le M.. 64

只是我想要测试私有方法的两个例子:

  1. 解密例程 - 我不想让任何人看到它只是为了测试,否则任何人都可以使用它们来解密.但它们是代码固有的,复杂的,并且需要始终工作(明显的例外是反射,在大多数情况下,甚至可以用来查看私有方法,当SecurityManager没有配置来防止这种情况时).
  2. 创建用于社区消费的SDK.在这里公共具有完全不同的含义,因为这是整个世界可能看到的代码(不仅仅是我的应用程序的内部代码).如果我不希望SDK用户看到它,我会将代码放入私有方法中 - 我不认为这是代码味道,仅仅是SDK编程的工作方式.但是我当然还需要测试我的私有方法,它们实际上是SDK的功能所在.

我理解只测试"合同"的想法.但是我没有看到人们可以提倡实际上没有测试代码 - 你的里程可能会有所不同.

因此,我的权衡涉及使JUnits与反射复杂化,而不是损害我的安全性和SDK.

  • 虽然你永远不应该公开方法来测试它,但是`private`并不是唯一的选择.没有访问修饰符是"包私有",并且只要您的单元测试位于同一个包中,就意味着您可以对其进行单元测试. (4认同)
  • 感谢您为每个人提供真实的例子.大多数答案都很好,但从理论的角度来看.在现实世界中,我们确实需要隐藏合同中的实现,我们仍然需要对其进行测试.阅读所有这些,我想也许这应该是一个全新的测试级别,具有不同的名称 (2认同)

Thomas Owens.. 56

私有方法由公共方法调用,因此公共方法的输入还应测试由这些公共方法调用的私有方法.当公共方法失败时,那可能是私有方法失败.


supernova.. 37

我使用的另一种方法是将私有方法更改为包私有或受保护,然后使用Google Guava库的@VisibleForTesting注释对其进行补充.

这将告诉使用此方法的任何人要小心,即使在包中也不能直接访问它.另外,测试类不需要在物理上相同的包中,而是在测试文件夹下的相同包中.

例如,如果要测试的方法是,src/main/java/mypackage/MyClass.java那么应该放入测试调用src/test/java/mypackage/MyClassTest.java.这样,您就可以访问测试类中的测试方法.

  • 对我来说,这就像是在说,不要给您的消防员一个一次性的钥匙来测试消防演习,而是让您的前门处于解锁状态,并在门上写上一个标语:“已解锁进行测试-如果您不是从我们的公司,请不要输入”。 (2认同)

phareim.. 33

为了测试大和古怪类遗留代码,它往往是能够测试一个私人(或公共)方法我正在写非常有帮助的现在.

我使用junitx.util.PrivateAccessor -package for Java.许多有用的单行程序用于访问私有方法和私有字段.

import junitx.util.PrivateAccessor;

PrivateAccessor.setField(myObjectReference, "myCrucialButHardToReachPrivateField", myNewValue);
PrivateAccessor.invoke(myObjectReference, "privateMethodName", java.lang.Class[] parameterTypes, java.lang.Object[] args);

  • 请务必下载整个JUnit-addons(http://sourceforge.net/projects/junit-addons/)软件包,而不是Source Forge-Recommended Project PrivateAccessor. (2认同)
  • 当你在这些方法中使用`Class`作为第一个参数时,确保只访问`static`成员. (2认同)

Grundlefleck.. 27

在尝试了使用 Java 反射的 Cem Catikkas 解决方案之后,我不得不说他的解决方案比我在这里描述的更优雅.但是,如果您正在寻找使用反射的替代方法,并且可以访问您正在测试的源,那么这仍然是一个选项.

测试类的私有方法可能是有用的,特别是在测试驱动开发中,您希望在编写任何代码之前设计小型测试.

创建可访问私有成员和方法的测试可以测试难以专门定位的代码区域,只能访问公共方法.如果公共方法涉及多个步骤,则它可以包含多个私有方法,然后可以单独进行测试.

好处:

  • 可以测试更精细的粒度

缺点:

  • 测试代码必须与源代码位于同一文件中,这可能更难以维护
  • 与.class输出文件类似,它们必须保持在源代码中声明的相同包中

但是,如果连续测试需要这种方法,则可能是应该提取私有方法的信号,可以以传统的公共方式进行测试.

这是一个如何工作的复杂的例子:

// Import statements and package declarations

public class ClassToTest
{
    private int decrement(int toDecrement) {
        toDecrement--;
        return toDecrement;
    }

    // Constructor and the rest of the class

    public static class StaticInnerTest extends TestCase
    {
        public StaticInnerTest(){
            super();
        }

        public void testDecrement(){
            int number = 10;
            ClassToTest toTest= new ClassToTest();
            int decremented = toTest.decrement(number);
            assertEquals(9, decremented);
        }

        public static void main(String[] args) {
            junit.textui.TestRunner.run(StaticInnerTest.class);
        }
    }
}

内部类将被编译为ClassToTest$StaticInnerTest.

另请参阅:Java技巧106:用于娱乐和利润的静态内部类


Mikhail.. 26

Spring Framework中,您可以使用此方法测试私有方法:

ReflectionTestUtils.invokeMethod()

例如:

ReflectionTestUtils.invokeMethod(TestClazz, "createTest", "input data");


TofuBeer.. 24

正如其他人所说......不要直接测试私人方法.以下是一些想法:

  1. 保持所有方法小而集中(易于测试,易于发现错误)
  2. 使用代码覆盖工具.我喜欢Cobertura(哦,快乐的一天,看起来像是一个新版本!)

在单元测试上运行代码覆盖率.如果您发现方法未经过全面测试,请添加测试以获得覆盖率.瞄准100%的代码覆盖率,但意识到你可能不会得到它.


Antony Booth.. 24

私有方法由公共方法使用.否则,它们就是死代码.这就是为什么你测试公共方法,断言公共方法的预期结果,从而断言它消耗的私有方法.

在对公共方法运行单元测试之前,应通过调试来测试私有方法的测试.

它们也可以使用测试驱动开发进行调试,调试单元测试直到满足所有断言.

我个人认为使用TDD创建类更好; 创建公共方法存根,然后使用预先定义的所有断言生成单元测试,因此在编码之前确定方法的预期结果.这样,您就不会走错路径,使单元测试断言符合结果.您的课程非常强大,并且在所有单元测试通过后都符合要求.

  • 虽然这是真的,但它可能导致一些非常复杂的测试 - 它是一次测试单个方法(单元测试)而不是整组测试的更好模式.这不是一个可怕的建议,但我认为这里有更好的答案 - 这应该是最后的选择. (2认同)

Steve Chambe.. 23

如果使用Spring,ReflectionTestUtils提供了一些方便的工具,只需要很少的工作就可以帮助你.例如,要在私有成员上设置模拟而不必强制添加不需要的公共setter:

ReflectionTestUtils.setField(theClass, "theUnsettableField", theMockObject);


Don Kirkby.. 22

如果您正在尝试测试您不愿意或无法更改的现有代码,那么反射是一个不错的选择.

如果类的设计仍然是灵活的,并且你有一个复杂的私有方法,你想单独测试,我建议你把它拉出一个单独的类并分别测试该类.这不必更改原始类的公共接口; 它可以在内部创建辅助类的实例并调用辅助方法.

如果您想测试来自辅助方法的困难错误条件,您可以更进一步.从helper类中提取一个接口,将一个公共getter和setter添加到原始类中以注入帮助器类(通过其接口使用),然后将一个helper类的模拟版本注入到原始类中以测试原始类的方式响应助手的异常.如果您想在不测试帮助程序类的情况下测试原始类,这种方法也很有用.


ema.. 17

测试私有方法会破坏类的封装,因为每次更改内部实现时都会破坏客户端代码(在本例中为测试).

所以不要测试私有方法.

  • 单元测试和src代码是一对.如果更改了src,可能需要更改单元测试.这是junit测试的意义.他们应该像以前那样为所有工作服务.如果你改变代码,它们就会破坏. (4认同)

Will Sargent.. 16

如果您想测试遗留应用程序的私有方法,而您无法更改代码,那么Java的一个选项是jMockit,它允许您为对象创建模拟,即使它们是该类的私有对象.

  • 作为jmockit库的一部分,您可以访问Deencapsulation类,它可以轻松地测试私有方法:`Deencapsulation.invoke(instance,"privateMethod",param1,param2); (4认同)

simpatico.. 16

JUnit.org FAQ页面的答案:

但如果你必须......

如果您使用的是JDK 1.3或更高版本,则可以使用反射在PrivilegedAccessor的帮助下破坏访问控制机制.有关如何使用它的详细信息,请阅读本文.

如果您使用的是JDK 1.6或更高版本并使用@Test注释测试,则可以使用Dp4j在测试方法中注入反射.有关如何使用它的详细信息,请参阅此测试脚本.

PS我是Dp4j的主要贡献者,问是否需要帮助.:)


bmurphy1976.. 14

我倾向于不测试私有方法.有疯狂.就个人而言,我相信你应该只测试你公开的接口(包括受保护的和内部的方法).


Joe.. 14

如果您正在使用JUnit,请查看junit-addons.它能够忽略Java安全模型并访问私有方法和属性.


GROX13.. 13

我建议你稍微重构一下你的代码.当你不得不开始考虑使用反射或其他类型的东西时,为了测试你的代码,你的代码就会出现问题.

你提到了不同类型的问题.让我们从私人领域开始.在私有字段的情况下,我会添加一个新的构造函数并将注入的字段注入其中.而不是这个:

public class ClassToTest {

    private final String first = "first";
    private final List<String> second = new ArrayList<>();
    ...
}

我用过这个:

public class ClassToTest {

    private final String first;
    private final List<String> second;

    public ClassToTest() {
        this("first", new ArrayList<>());
    }

    public ClassToTest(final String first, final List<String> second) {
        this.first = first;
        this.second = second;
    }
    ...
}

即使使用一些遗留代码,这也不会成为问题.旧代码将使用空构造函数,如果您问我,重构代码看起来更干净,并且您将能够在没有反射的情况下在测试中注入必要的值.

现在关于私人方法.根据我个人的经验,当您必须存根私有方法进行测试时,该方法与该类无关.在这种情况下,一个常见的模式是包装在一个接口中,Callable然后你也在构造函数中传入该接口(使用那个多个构造函数技巧):

public ClassToTest() {
    this(...);
}

public ClassToTest(final Callable<T> privateMethodLogic) {
    this.privateMethodLogic = privateMethodLogic;
}

我写的大部分内容看起来都是依赖注入模式.根据我的个人经验,它在测试时非常有用,我认为这种代码更清晰,更易于维护.关于嵌套类,我会说同样的.如果嵌套类包含重逻辑,那么如果将它作为包私有类移动并将其注入需要它的类中会更好.

我在重构和维护遗留代码时也使用了其他几种设计模式,但这完全取决于要测试的代码的情况.使用反射主要不是问题,但是当你有一个经过严格测试的企业应用程序并且在每次部署之前运行测试时,一切都变得非常慢(这很烦人,而且我不喜欢那种东西).

还有二次注射,但我不建议使用它.我最好坚持使用构造函数并在必要时初始化所有内容,留下注入必要依赖项的可能性.

  • 你能解释为什么它会让类ClassToTest更难维护吗?实际上,它使您的应用程序更易于维护,您建议为"第一"和"第二"变量中的每个不同值创建新类? (2认同)

loknath.. 12

私有方法只能在同一个类中访问.因此,无法从任何测试类测试目标类的"私有"方法.一种方法是您可以手动执行单元测试,也可以将方法从"私有"更改为"受保护".

然后,只能在定义类的同一个包中访问受保护的方法.因此,测试目标类的受保护方法意味着我们需要在与目标类相同的包中定义测试类.

如果以上所有内容都不符合您的要求,请使用反射方式访问私有方法.


Darren Greav.. 11

正如上面提到的那样,一个好方法是通过公共接口测试它们.

如果你这样做,最好使用代码覆盖工具(如Emma)来查看你的私有方法是否实际上是从你的测试中执行的.


Yuli Reiri.. 11

这是我测试私有字段的通用函数:

protected <F> F getPrivateField(String fieldName, Object obj)
    throws NoSuchFieldException, IllegalAccessException {
    Field field =
        obj.getClass().getDeclaredField(fieldName);

    field.setAccessible(true);
    return (F)field.get(obj);
}


Snicolas.. 10

今天,我推出了一个Java库来帮助测试私有方法和字段.它在设计时考虑到了Android,但它确实可以用于任何Java项目.

如果您获得了一些私有方法或字段或构造函数的代码,则可以使用BoundBox.它完全符合您的要求.下面是一个测试示例,该测试访问Android活动的两个私有字段以对其进行测试:

@UiThreadTest
public void testCompute() {

    // Given
    boundBoxOfMainActivity = new BoundBoxOfMainActivity(getActivity());

    // When
    boundBoxOfMainActivity.boundBox_getButtonMain().performClick();

    // Then
    assertEquals("42", boundBoxOfMainActivity.boundBox_getTextViewMain().getText());
}

BoundBox可以轻松测试私有/受保护的字段,方法和构造函数.您甚至可以访问通过继承隐藏的内容.实际上,BoundBox打破了封装.它将允许您通过反射访问所有这些,但是在编译时检查所有内容.

它是测试一些遗留代码的理想选择.仔细使用它.;)

https://github.com/stephanenicolas/boundbox


小智.. 10

请看下面的例子;

应添加以下import语句:

import org.powermock.reflect.Whitebox;

现在,您可以直接传递具有私有方法,要调用的方法名称以及其他参数的对象,如下所示.

Whitebox.invokeMethod(obj, "privateMethod", "param1");


Aaron.. 8

首先,我会抛出这个问题:为什么你的私人成员需要隔离测试?它们是否复杂,提供如此复杂的行为以至于需要在公共场所进行测试?它是单元测试,而不是"代码行"测试.不要出汗小东西.

如果他们那么大,足够大,以至于这些私人成员都是一个复杂性很大的"单位" - 考虑重构这些私人成员.

如果重构不合适或不可行,您可以使用策略模式在单元测试下替换对这些私有成员函数/成员类的访问吗?在单元测试下,该策略将提供额外的验证,但在发布版本中,它将是简单的直通.

  • 因为通常来自公共方法的特定代码片段被重构为内部私有方法,并且实际上是您可能出错的关键逻辑部分.您希望独立于公共方法进行测试 (3认同)

CoronA.. 8

我最近遇到了这个问题并编写了一个名为Picklock的小工具,它避免了显式使用Java反射API的问题,两个例子:

调用方法,例如private void method(String s)- 通过Java反射

Method method = targetClass.getDeclaredMethod("method", String.class);
method.setAccessible(true);
return method.invoke(targetObject, "mystring");

调用方法,例如private void method(String s)- 由Picklock

interface Accessible {
  void method(String s);
}

...
Accessible a = ObjectAccess.unlock(targetObject).features(Accessible.class);
a.method("mystring");

设置字段,例如private BigInteger amount;- 通过Java反射

Field field = targetClass.getDeclaredField("amount");
field.setAccessible(true);
field.set(object, BigInteger.valueOf(42));

设置字段,例如private BigInteger amount;- 由Picklock

interface Accessible {
  void setAmount(BigInteger amount);
}

...
Accessible a = ObjectAccess.unlock(targetObject).features(Accessible.class);
a.setAmount(BigInteger.valueOf(42));


Josh Brown.. 6

对于Java我会使用反射,因为我不喜欢只是为了测试而在声明的方法上更改对包的访问的想法.但是,我通常只测试公共方法,这也应该确保私有方法正常工作.

您不能使用反射从所有者类外部获取私有方法,私有修饰符也会影响反射

这不是真的.你肯定可以,正如Cem Catikkas的回答中提到的那样.


seyed mohamm.. 6

在c ++中:在包含具有要对其进行测试的私有函数的类头之前

使用此代码:

#define private public
#define protected public


Victor Grazi.. 6

PowerMockito就是为此而制造的.使用maven依赖

<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-mockito-release-full</artifactId>
    <version>1.6.4</version>
</dependency>

那你可以做

import org.powermock.reflect.Whitebox;
...
MyClass sut = new MyClass();
SomeType rval = Whitebox.invokeMethod(sut, "myPrivateMethod", params, moreParams);


归档时间:

查看次数:

819316 次

最近记录:

8 月,2 周 前