[英]Unit Test public method that calls private method and other objects in Java
[英]Java Unit Test: Test from public method or package private method
我有一个 class Price
和一个公共方法calculate()
,它调用另一个私有方法calculateByA()
。
public class Price {
public SomeObject calculate() {
if(someCondition) {
calculateByA()
// ....
} else {
//Calculate something else
}
}
private int calculateByA() {
//calculation logic
}
}
我想做一个单元测试来测试calculationByA()
的逻辑。
我曾想过:
calculate()
进行测试并将someCondition
设置为true
。calculateByA()
更改为 package-private 并在测试中直接调用它。但是,我不确定哪种方法更好。
我非常不喜欢使用 powermock 等。 问题不在于它们让您绕过可见性系统(其他语言根本不需要,例如参见 python),而是您尝试测试实现细节。
为可见方法编写测试并观察其私有方法的副作用。 在您的示例中,例如在 someCondition 中测试,您的结果与这种情况下的预期相符。 如果您因为有很多私有方法而遇到问题,请考虑使用 package 并将您的代码拆分 - 无论如何它可能太大了。 也使用 DI 卢克!
您的问题有三个选项。 最终取决于您自己的情况。 但是,这里有一些关于如何在它们之间进行选择的想法:
在您提到的情况下,您可以使用正确的配置调用calculate
来执行calculateByA
。 我认为这是最好的方法。 代码的结构意味着calculate
是访问calculateByA
的公共接口。 这意味着当这种行为发生变化时,您的测试将提醒人们注意问题。 这反过来意味着 class 的用户将体验到行为上的变化。
正如您所提到的,这将允许您从同一 package 中的其他类(包括单元测试类)调用calculateByA
。 这无疑是一种允许对calculateByA
进行简单且独立的单元测试的方法。 但是,我不喜欢这样,仅仅是因为您只希望通过calculate
function 访问,并且通过更改访问权限,同一 package 中的其他类很容易直接调用calculateByA
。
有许多技术允许您在测试中直接调用私有方法。 我不会重复@Tiemo Vorschütz 的出色回答,其中详细介绍了如何执行此操作。 然而,这将是我最后的手段。 简单的反射测试更加脆弱,并且增加了测试套件的维护成本。
PowerMock 让您可以直接测试您的私有方法:
价格.java:
import java.util.concurrent.ThreadLocalRandom;
public class Price {
private final boolean someCondition;
public Price(final boolean someCondition) {
this.someCondition = someCondition;
}
public int calculate() {
if (someCondition) {
return calculateByA();
} else {
// Calculate something else
return 0;
}
}
private int calculateByA() {
final int randomNum = ThreadLocalRandom.current().nextInt(0, 10 + 1);
return 4711 * randomNum;
}
}
PriceTest.java:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
@RunWith(PowerMockRunner.class)
@PrepareForTest(Price.class)
public class PriceTest {
/*
* Refelection test for a single private method
*/
@Test
public void calculateByA() throws Exception {
final Price instance = new Price(true);
final int result = Whitebox.invokeMethod(instance, "calculateByA");
System.out.println(result);
}
/*
* Test public method calculate which invokes private method calculateByA
*/
@Test
public void testCalculate() throws Exception {
final Price instance = new Price(true);
System.out.println(instance.calculate());
}
}
JUnit4 旁边的依赖项:
</properties>
<powermock.version>2.0.2</powermock.version>
</properties>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.28.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.