构造函数依赖注入测试类及FixValueConceptIntegration类Mock测试咨询
构造函数依赖注入改造 + Mock测试实现指南
咱们先明确核心问题:原来的FixValueConceptIntegration类通过单例工厂硬编码获取依赖,导致测试时无法替换成Mock对象。解决思路就是把硬依赖改成构造函数注入,同时兼容现有业务代码,然后用Mockito这类框架快速实现Mock测试。
第一步:改造原类的构造函数
先给类新增一个带依赖参数的构造函数,同时保留原无参构造来兼容现有业务逻辑(如果不需要兼容的话,也可以直接去掉无参构造):
private ReferenceConceptHelper referenceConceptHelper; private ConceptClientFacade conceptClientExternalFacade; // 新增:用于依赖注入的构造函数(测试时用这个传Mock对象) public FixValueConceptIntegration(ReferenceConceptHelper referenceConceptHelper, ConceptClientFacade conceptClientExternalFacade) { this.referenceConceptHelper = referenceConceptHelper; this.conceptClientExternalFacade = conceptClientExternalFacade; } // 保留原无参构造,兼容现有业务代码 public FixValueConceptIntegration() { this(JournalSingletonFactory.getInstance().getSingletonInstance(ReferenceConceptHelper.class), JournalSingletonFactory.getInstance().getSingletonInstance(ConceptClientFacade.class)); }
这样改造后,业务代码依然可以用new FixValueConceptIntegration()创建实例,而测试时我们可以用带参构造传入Mock对象。
第二步:用Mockito编写测试类
Mockito是Java生态中最常用的Mock框架,上手简单且功能强大。下面是完整的测试示例(基于JUnit 5):
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import static org.mockito.Mockito.*; // 启用Mockito扩展,自动初始化Mock对象 @ExtendWith(MockitoExtension.class) class FixValueConceptIntegrationTest { // 创建Mock对象:模拟ReferenceConceptHelper的行为 @Mock private ReferenceConceptHelper mockReferenceConceptHelper; // 创建Mock对象:模拟ConceptClientFacade的行为 @Mock private ConceptClientFacade mockConceptClientExternalFacade; // 自动将上面的Mock对象注入到测试类实例中 @InjectMocks private FixValueConceptIntegration fixValueConceptIntegration; @Test void testYourBusinessMethod() { // 1. 定义Mock对象的预期行为:比如调用某个方法时返回指定结果 when(mockReferenceConceptHelper.getSomeValue(anyString())) .thenReturn("mock_fix_value"); // 2. 调用被测试的业务方法 String result = fixValueConceptIntegration.yourBusinessMethod("test_param"); // 3. 验证结果是否符合预期(可选) // assertEquals("expected_result", result); // 4. 验证Mock方法是否被正确调用(可选,但能确保逻辑走了正确的分支) verify(mockReferenceConceptHelper, times(1)).getSomeValue("test_param"); } }
关键注解说明:
@ExtendWith(MockitoExtension.class):JUnit 5的扩展,负责初始化所有标注了@Mock的对象,并处理@InjectMocks的注入逻辑。@Mock:创建一个Mock实例,你可以自定义它的方法返回值、抛出异常等行为。@InjectMocks:Mockito会自动将同类型的Mock对象注入到这个实例中(因为我们已经有带参构造,它会自动匹配参数类型完成注入)。
备选方案:如果暂时不能修改原类(不推荐)
如果因为业务限制暂时无法修改原类的构造函数,也可以用PowerMock来Mock单例工厂,但这种方式侵入性强,不利于代码维护,仅作为临时方案:
import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import static org.mockito.Mockito.when; @RunWith(PowerMockRunner.class) @PrepareForTest(JournalSingletonFactory.class) class FixValueConceptIntegrationTest { @Mock private ReferenceConceptHelper mockReferenceConceptHelper; @Mock private ConceptClientFacade mockConceptClientExternalFacade; @Test void testWithPowerMock() { // Mock单例工厂的静态方法 PowerMockito.mockStatic(JournalSingletonFactory.class); when(JournalSingletonFactory.getInstance().getSingletonInstance(ReferenceConceptHelper.class)) .thenReturn(mockReferenceConceptHelper); when(JournalSingletonFactory.getInstance().getSingletonInstance(ConceptClientFacade.class)) .thenReturn(mockConceptClientExternalFacade); // 创建原类实例(此时会获取到我们Mock的对象) FixValueConceptIntegration testInstance = new FixValueConceptIntegration(); // 后续测试逻辑... } }
总结
优先推荐改造构造函数实现依赖注入,这不仅让测试更简单,也符合依赖倒置原则,让代码更具扩展性和可维护性。Mockito是Mock测试的首选框架,学习成本低,社区资源丰富。
内容的提问来源于stack exchange,提问作者chamzz.dot
相关产品推荐
相关产品推荐

