如何使用JUnit测试具有内部私有方法、字段或嵌套类的类?
仅仅为了能够运行测试而更改方法的访问修饰符似乎是不好的。
如何使用JUnit测试具有内部私有方法、字段或嵌套类的类?
仅仅为了能够运行测试而更改方法的访问修饰符似乎是不好的。
当前回答
测试私有方法的最佳方法是通过另一个公共方法。如果无法做到这一点,则以下条件之一为真:
私有方法是死代码您正在测试的类附近有设计气味您尝试测试的方法不应是私有的
其他回答
我感觉完全一样。。。更改一个方法的访问修饰符,以便能够运行测试,这对我来说是个坏主意。在我们公司,我们也进行了很多讨论,在我看来,测试私有方法的好方法是使用Java反射或其他框架,使方法可测试。对于复杂的私有方法,我多次这样做,这有助于保持测试的小型性、可读性和可维护性。
在我阅读了这里的所有答案之后,我只是不同意那些说“如果你需要测试私有方法,那么会有代码气味”或甚至“不要测试私有方法”的人。。。所以我给你举个小例子:
假设我有一个带有一个公共方法和两个私有方法的类:
public class ConwaysGameOfLife {
private boolean[][] generationData = new boolean[128][128];
/**
* Compute the next generation and return the new state
* Also saving the new state in generationData
*/
public boolean[][] computeNextGeneration() {
boolean[][] tempData = new boolean[128][128];
for (int yPos=0; yPos<=generationData.length; yPos++) {
for (int xPos=0; xPos<=generationData[yPos].length; xPos++) {
int neighbors = countNeighbors(yPos, xPos);
tempData[yPos][xPos] = determineCellState(neighbors, yPos, xPos);
}
}
generationData = tempData;
return generationData;
}
/**
* Counting the neighbors for a cell on given position considering all the edge cases
*
* @return the amount of found neighbors for a cell
*/
private int countNeighbors(int yPos, int xPos) {}
/**
* Determine the cell state depending on the amount of neighbors of a cell and on a current state of the cell
*
* @return the new cell state
*/
private boolean determineCellState(int neighborsAmount, int yPos, int xPos) {}
}
因此,至少对于“countNeighbors”方法,我需要测试八个边缘情况和一些一般情况(直接位于角落的单元格、直接位于矩阵边缘的单元格和位于中间的单元格)。因此,如果我只是试图通过“computeNextGeneration”方法覆盖所有的情况,并且在重构之后,一些测试是红色的,那么识别错误所在的位置可能需要花费时间。
如果我分别测试“determineCellState”和“countNeighbors”,并且在重构和优化之后,“computeNextGeneration”和“determine CellState”的测试是红色的,那么我很确定错误将出现在“determiseCellState”方法中。
此外,如果您从一开始就为这些方法编写单元测试,这些测试将帮助您开发方法/算法,而无需考虑和包装公共方法中的其他方法调用和案例。你只需要在方法中编写快速的小测试来覆盖你的案例。。。例如,如果名为“countNeighbors_should_return_right_amount_of_noughbors_for_the_right_top_corner_cell()”的测试失败,那么很清楚在哪里查找错误。
下面是我测试私有字段的通用函数:
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);
}
我倾向于不测试私人方法。这里有疯狂。我个人认为,你应该只测试你公开的接口(包括受保护的和内部的方法)。
在C++中:在包含包含要测试的私有函数的类头之前。
使用此代码:
#define private public
#define protected public
在过去,我曾为Java使用过反射,在我看来这是一个很大的错误。
严格来说,您不应该编写直接测试私有方法的单元测试。您应该测试的是类与其他对象的公共契约;您不应该直接测试对象的内部。如果另一个开发人员想要对类进行一个小的内部更改,这不会影响类的公共契约,那么他/她就必须修改基于反射的测试,以确保它正常工作。如果在整个项目中重复这样做,那么单元测试就不再是代码健康状况的有用度量,而开始成为开发的障碍,成为开发团队的烦恼。
相反,我建议使用一个代码覆盖工具,例如Cobertura,以确保您编写的单元测试在私有方法中提供代码的适当覆盖。通过这种方式,您可以间接测试私有方法正在做什么,并保持更高级别的灵活性。