
当需要在java中测试一个公共方法,而该方法内部又调用了一个私有方法,且该私有方法通过`new`关键字创建了待测试对象时,直接使用传统mocking框架(如mockito)来模拟这个内部创建的对象是不可行的。本文将深入探讨这一挑战,并提供一种标准且推荐的解决方案:通过引入可注入的工厂模式来重构代码,从而实现对内部依赖的有效模拟和测试。
在Java单元测试中,我们经常使用Mocking框架(如Mockito)来隔离被测试单元与其依赖,以确保测试的独立性和专注性。然而,当一个对象在被测试类的一个私有方法内部通过new关键字直接实例化时,传统的Mocking技术会遇到瓶颈。这是因为Mocking框架通常通过代理或字节码修改来拦截对现有对象方法的调用,但它们无法干预方法内部的局部变量创建过程,特别是当这些对象是直接通过new操作符构造时。
考虑以下场景:一个ParentClass包含一个公共方法method1,它内部调用了一个私有方法privateMethod。privateMethod负责创建并返回一个ObjectNeeded2Mock的实例。
// 待测试的依赖对象
class ObjectNeeded2Mock {
public String doSomething() {
return "Real Value";
}
// 更多业务逻辑
}
// 私有方法内部创建依赖对象的类
class ParentClass {
public ParentClass() {}
public String method1(String argument) {
// ... 其他逻辑
Obj resultObj = privateMethod(argument); // 调用私有方法
return "Processed: " + resultObj.getValue();
}
private Obj privateMethod(String argument) {
// 问题所在:ObjectNeeded2Mock在这里被直接实例化
ObjectNeeded2Mock obj = new ObjectNeeded2Mock();
String processedValue = obj.doSomething() + " " + argument;
return new Obj(processedValue);
}
}
// 辅助类
class Obj {
private String value;
public Obj(String value) { this.value = value; }
public String getValue() { return value; }
}在这种结构下,如果我们想在测试method1时,模拟ObjectNeeded2Mock的行为,会发现难以实现。@InjectMock注解通常用于将Mock对象注入到被测试对象的字段中,但它无法改变私有方法内部的局部变量创建行为。
解决此问题的最佳实践是重构代码,以允许对ObjectNeeded2Mock的创建过程进行控制。核心思想是:不要在privateMethod中直接new对象,而是将对象的创建职责委托给一个可注入的工厂。
立即学习“Java免费学习笔记(深入)”;
步骤一:定义工厂接口和实现
首先,为ObjectNeeded2Mock的创建定义一个工厂接口,并提供一个默认实现。
// 1. 定义一个工厂接口
interface ObjectNeeded2MockFactory {
ObjectNeeded2Mock create();
}
// 2. 提供一个默认的工厂实现
class DefaultObjectNeeded2MockFactory implements ObjectNeeded2MockFactory {
@Override
public ObjectNeeded2Mock create() {
return new ObjectNeeded2Mock(); // 实际创建对象
}
}步骤二:重构ParentClass以使用工厂
修改ParentClass,使其通过构造函数(或其他注入方式)接收ObjectNeeded2MockFactory的实例,并在privateMethod中使用该工厂来创建ObjectNeeded2Mock。
// 3. 重构ParentClass,通过构造函数注入工厂
class ParentClass {
private final ObjectNeeded2MockFactory factory;
// 构造函数注入工厂
public ParentClass(ObjectNeeded2MockFactory factory) {
this.factory = factory;
}
public String method1(String argument) {
// ... 其他逻辑
Obj resultObj = privateMethod(argument);
return "Processed: " + resultObj.getValue();
}
private Obj privateMethod(String argument) {
// 现在通过工厂创建ObjectNeeded2Mock
ObjectNeeded2Mock obj = factory.create();
String processedValue = obj.doSomething() + " " + argument;
return new Obj(processedValue);
}
}步骤三:编写测试代码
现在,在测试ParentClass时,我们可以轻松地模拟ObjectNeeded2MockFactory,并控制它返回的ObjectNeeded2Mock实例。
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
class ParentClassTest {
private ObjectNeeded2MockFactory mockFactory;
private ObjectNeeded2Mock mockObjectNeeded2Mock;
private ParentClass parentClass;
@BeforeEach
void setUp() {
// 1. Mock工厂接口
mockFactory = mock(ObjectNeeded2MockFactory.class);
// 2. Mock ObjectNeeded2Mock实例
mockObjectNeeded2Mock = mock(ObjectNeeded2Mock.class);
// 3. 配置mockFactory,使其在调用create()时返回mockObjectNeeded2Mock
when(mockFactory.create()).thenReturn(mockObjectNeeded2Mock);
// 4. 使用mockFactory实例化ParentClass
parentClass = new ParentClass(mockFactory);
}
@Test
void testMethod1_withMockedDependency() {
// Arrange
String testArgument = "testArgument";
String mockedResultFromObj = "Mocked Result";
// 配置mockObjectNeeded2Mock的行为
when(mockObjectNeeded2Mock.doSomething()).thenReturn(mockedResultFromObj);
// Act
String actualResult = parentClass.method1(testArgument);
// Assert
// 验证工厂的create方法是否被调用
verify(mockFactory, times(1)).create();
// 验证mockObjectNeeded2Mock的doSomething方法是否被调用
verify(mockObjectNeeded2Mock, times(1)).doSomething();
// 验证最终结果是否符合预期
String expectedResult = "Processed: " + mockedResultFromObj + " " + testArgument;
assertEquals(expectedResult, actualResult);
}
}当Java私有方法内部通过new关键字创建了依赖对象时,直接对其进行Mocking是不可行的。解决此问题的标准方法是采用可注入的工厂模式。通过将对象的创建职责委托给一个工厂接口,并将其注入到主类中,我们可以在测试时轻松地模拟这个工厂,从而控制内部创建的依赖对象的行为。这种重构不仅解决了测试难题,也通常会提升代码的设计质量和可维护性。
以上就是Java中测试私有方法内部创建的对象:使用可注入工厂模式的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号