You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Mockito和TestNG模拟方法内部创建的对象

问题:Mock方法内部创建的依赖类实例,使其返回指定值

业务代码

public class MyClass {
    public boolean myMethod() {
        DependentClass dependentObject = new DependentClass();
        return dependentObject.dependentMethod();
    }
}

class DependentClass {
    public boolean dependentMethod() {
        // Original behavior
        return true;
    }
}

无效的测试代码

import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class MyClassTest {

    @Mock
    private DependentClass dependentClassMock;

    @InjectMocks
    private MyClass myClass;

    @BeforeMethod
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testMyMethod() {
        // Arrange
        Mockito.when(dependentClassMock.dependentMethod()).thenReturn(false);

        // Act
        boolean result = myClass.myMethod();

        // Assert
        Assert.assertFalse(result);
    }
}

问题核心:myMethod内直接通过new DependentClass()创建实例,导致@InjectMocks注入的Mock对象完全没被用到,测试结果始终返回true。需要实现Mock该内部实例,且尽可能少修改原代码。


方案1:小幅度重构MyClass(推荐,符合依赖注入原则)

仅新增一个构造方法用于测试注入Mock,保留原无参构造兼容现有业务逻辑,无侵入性:

修改后的MyClass:

public class MyClass {
    private DependentClass dependentObject;

    // 保留原无参构造,不影响现有调用
    public MyClass() {
        this.dependentObject = new DependentClass();
    }

    // 新增构造方法,用于测试注入Mock实例
    public MyClass(DependentClass dependentObject) {
        this.dependentObject = dependentObject;
    }

    public boolean myMethod() {
        return dependentObject.dependentMethod();
    }
}

对应的有效测试代码:

import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class MyClassTest {

    @Mock
    private DependentClass dependentClassMock;

    private MyClass myClass;

    @BeforeMethod
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        // 通过带参构造注入Mock实例
        myClass = new MyClass(dependentClassMock);
    }

    @Test
    public void testMyMethod() {
        Mockito.when(dependentClassMock.dependentMethod()).thenReturn(false);

        boolean result = myClass.myMethod();

        Assert.assertFalse(result);
    }
}

方案2:使用Mockito PowerMock(无需修改原代码)

如果完全不想改动业务代码,可以用PowerMock拦截类的构造行为,强制返回Mock实例:

测试代码:

import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.testng.PowerMockTestCase;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

@PrepareForTest(MyClass.class) // 告知PowerMock需要修改MyClass的字节码
public class MyClassTest extends PowerMockTestCase {

    @Mock
    private DependentClass dependentClassMock;

    private MyClass myClass;

    @BeforeMethod
    public void setUp() {
        myClass = new MyClass();
    }

    @Test
    public void testMyMethod() throws Exception {
        // 拦截DependentClass的无参构造,返回Mock实例
        PowerMockito.whenNew(DependentClass.class).withNoArguments().thenReturn(dependentClassMock);
        // 指定Mock方法的返回值
        Mockito.when(dependentClassMock.dependentMethod()).thenReturn(false);

        boolean result = myClass.myMethod();

        Assert.assertFalse(result);
        // 验证构造方法被调用一次
        PowerMockito.verifyNew(DependentClass.class).withNoArguments();
    }
}

注意:PowerMock通过修改字节码实现拦截,会增加测试复杂度,仅在无法重构业务代码时使用。


内容的提问来源于stack exchange,提问作者TechGoose

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 15:33:26