Answers:
通常,您不直接对私有方法进行单元测试。由于它们是私有的,因此请考虑将其作为实现细节。没有人会打电话给他们中的一个,并期望它以特定的方式工作。
相反,您应该测试您的公共接口。如果调用您的私有方法的方法按预期工作,则可以假定您的私有方法正常工作。
通常,我会避免这样做。如果您的私有方法如此复杂以至于需要单独的单元测试,则通常意味着它应该拥有自己的类。这可能会鼓励您以可重用的方式编写它。然后,您应该测试新类并在旧类中调用它的公共接口。
另一方面,有时将实现细节分解为单独的类会导致具有复杂接口的类,在新老类之间传递大量数据,或者从OOP的角度看可能看起来不错的设计,匹配来自问题域的直觉(例如,为了避免测试私有方法,将定价模型分为两部分不是很直观,并且可能在以后维护/扩展代码时导致问题)。您不想拥有总是一起更改的“孪生类”。
当在封装性和可测试性之间做出选择时,我宁愿选择第二个。拥有正确的代码(即产生正确的输出)比无法正常工作的好的OOP设计更为重要,因为它没有经过充分的测试。在Java中,您可以简单地授予方法“默认”访问权限,并将单元测试放在同一包中。单元测试只是您要开发的程序包的一部分,可以在测试和要测试的代码之间建立依赖关系。这意味着,当您更改实现时,可能需要更改测试,但是没关系-每次更改实现都需要重新测试代码,如果需要修改测试来做到这一点,则只需执行它。
通常,一类可能提供多个接口。有一个用户界面和一个维护者界面。第二个可以公开更多内容,以确保对代码进行适当的测试。它不必是对私有方法的单元测试,例如可以是日志记录。日志记录也会“破坏封装”,但是我们仍然这样做,因为它是如此有用。
私有方法的测试将取决于它们的复杂性;一些单行私有方法并不能真正保证测试的额外努力(这也可以说是公共方法),但是某些私有方法可能与公共方法一样复杂,并且很难通过公共接口进行测试。
我的首选技术是将私有方法包设为私有,这将允许访问同一包中的单元测试,但仍将其封装在所有其他代码中。这将带来直接测试私有方法逻辑的优势,而不必依靠公共方法测试来覆盖(可能)复杂逻辑的所有部分。
如果将其与Google Guava库中的@VisibleForTesting批注配对使用,则可以清楚地将此包私有方法标记为可见,仅用于测试,因此,任何其他类都不应调用该方法。
这种技术的反对者认为,这将破坏封装并打开私有方法以在同一程序包中进行编码。虽然我同意这样做会破坏封装并向其他类开放私有代码,但我认为测试复杂的逻辑比严格封装更重要,并且不使用明确标记为可见仅用于测试的包私有方法,这是开发人员的责任使用和更改代码库。
测试之前的私有方法:
private int add(int a, int b){
return a + b;
}
包私有方法准备测试:
@VisibleForTesting
int add(int a, int b){
return a + b;
}
注意:将测试放在同一包中并不等同于将它们放在同一物理文件夹中。通常,将主代码和测试代码分隔为单独的物理文件夹结构是一种好习惯,但是只要将类定义在同一软件包中,该技术就可以使用。
如果您不能使用外部API或不想使用外部API,您仍然可以使用纯标准JDK API通过反射来访问私有方法。这是一个例子
MyObject obj = new MyObject();
Method privateMethod = MyObject.class.getDeclaredMethod("getFoo", null);
privateMethod.setAccessible(true);
String returnValue = (String) privateMethod.invoke(obj, null);
System.out.println("returnValue = " + returnValue);
检查Java教程http://docs.oracle.com/javase/tutorial/reflect/或Java API http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/package-summary。 html以获得更多信息。
正如@kij在他的回答中所引用的那样,有时使用反射的简单解决方案确实可以很好地测试私有方法。
单元测试用例意味着测试代码单元。这并不意味着测试接口,因为如果您正在测试接口,则并不意味着您正在测试代码单元。这成为一种黑匣子测试。同样,比在接口级别确定问题然后尝试调试哪个模块不起作用,最好在最小的单元级别上查找问题。因此,无论其范围如何,都应对单元测试用例进行测试。以下是测试私有方法的一种方法。
如果使用的是Java,则可以使用提供Deencapsulation.invoke的jmockit来调用正在测试的类的任何私有方法。它最终使用反射来调用它,但是围绕它提供了一个不错的包装器。(https://code.google.com/p/jmockit/)
首先,正如其他作者所建议的:如果确实需要测试私有方法,请三思。如果是这样, ...
在.NET中,您可以将其转换为“内部”方法,并使程序包“ InternalVisible ”成为您的单元测试项目。
在Java中,您可以在要测试的类中编写测试本身,并且您的测试方法也应该能够调用私有方法。我实际上并没有丰富的Java经验,所以这可能不是最佳实践。
谢谢。
我通常会保护此类方法。假设您的课程位于:
src/main/java/you/Class.java
您可以通过以下方式创建测试类:
src/test/java/you/TestClass.java
现在,您可以访问受保护的方法并可以对其进行单元测试(JUnit或TestNG并不重要),但是您可以将这些方法保留给不需要的调用者。
请注意,这需要一个Maven风格的源树。
如果您真的需要测试私有方法,那么使用Java,您可以使用fest assert
和/或fest reflect
。它使用反射。
使用maven导入库(给定的版本不是我认为的最新版本)或直接将其导入类路径中:
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-reflect</artifactId>
<version>1.2</version>
</dependency>
例如,如果您有一个名为“ MyClass”的类,并且带有一个名为“ myPrivateMethod”的私有方法,该方法将一个String作为参数并将其值更新为“ this is cool testing!”,则可以执行以下junit测试:
import static org.fest.reflect.core.Reflection.method;
...
MyClass objectToTest;
@Before
public void setUp(){
objectToTest = new MyClass();
}
@Test
public void testPrivateMethod(){
// GIVEN
String myOriginalString = "toto";
// WHEN
method("myPrivateMethod").withParameterTypes(String.class).in(objectToTest).invoke(myOriginalString);
// THEN
Assert.assertEquals("this is cool testing !", myOriginalString);
}
该库还使您能够通过模拟替换任何bean属性(无论它们是私有的还是未写入setter),并将其与Mockito或任何其他模拟框架一起使用确实很酷。目前,您唯一需要了解的内容(不知道在下一版本中是否会更好)是您要操作的目标字段/方法的名称及其签名。
我通常在C#中所做的是使我的方法受保护而不是私有的。它是私有访问修饰符,但是它对所有未从被测类继承的类隐藏了该方法。
public class classUnderTest
{
//this would normally be private
protected void methodToTest()
{
//some code here
}
}
任何不直接从classUnderTest继承的类都不知道methodToTest甚至存在。在测试代码中,我可以创建一个特殊的测试类,该类可以扩展并提供对该方法的访问...
class TestingClass : classUnderTest
{
public void methodToTest()
{
//this returns the method i would like to test
return base.methodToTest();
}
}
此类仅存在于我的测试项目中。其唯一目的是提供对该单一方法的访问。它使我可以访问大多数其他班级没有的地方。
protected
是公共API的一部分,并受到相同的限制(永远不能更改,必须记录在案,...)。在C#中,您可以internal
与一起使用InternalsVisibleTo
。
如果将单元测试放在要测试的类的内部类中,则可以轻松地测试私有方法。使用TestNG,单元测试必须是使用@Test注释的公共静态内部类,如下所示:
@Test
public static class UserEditorTest {
public void test_private_method() {
assertEquals(new UserEditor().somePrivateMethod(), "success");
}
}
由于它是一个内部类,因此可以调用private方法。
我的测试是从maven运行的,它会自动找到这些测试用例。如果您只想测试一堂课,可以做
$ mvn test -Dtest=*UserEditorTest
资料来源:http : //www.ninthavenue.com.au/how-to-unit-test-private-methods