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

Mockito测试问题:测试One类method1时如何模拟Two类的method3方法

问题原因分析

你遇到的核心问题是:你测试代码里创建的spy two和One类内部实际持有的two是完全不同的对象。

看一下One的构造函数:它是自己直接new Two(this)生成了内部的two实例,而你在setup里创建的spy two并没有被One使用到,所以你对这个spy two的method3做的模拟自然不会生效。而method2能被成功模拟,是因为它属于你创建的spy one对象本身,调用的是同一个实例的方法。

解决方案

下面提供两种可行的解决思路,优先推荐第一种(代码重构),如果不能修改原代码再用第二种反射方案。

方案1:重构代码,使用依赖注入(推荐)

把Two的实例通过构造函数注入到One中,而不是让One自己创建Two,这样测试时可以直接传入Mock的Two实例。

修改原代码

class One {
    private final Two two;

    // 改为构造注入Two,而不是内部new
    public One(Two two) {
        this.two = two;
    }

    public void method1() {
        //do something
        method2();
    }

    public void method2() {
        //do something
        two.method3();
    }
}

class Two {
    private final One one;

    public Two(One one) {
        this.one = one;
    }

    public void method3() {
        //print something
    }
}

对应的JUnit测试代码

import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.mockito.Mockito.*;

public class OneTest {
    @Mock
    private Two mockTwo;
    private One one;

    @Before
    public void setup() {
        MockitoAnnotations.openMocks(this);
        // 把Mock的Two传入One的构造函数
        one = new One(mockTwo);
    }

    @Test
    public void testMethod1InClassOne() {
        // 模拟method3什么都不做
        doNothing().when(mockTwo).method3();
        
        one.method1();
        
        // 验证method3是否被调用了一次(可选,确保逻辑符合预期)
        verify(mockTwo, times(1)).method3();
    }
}

方案2:用反射替换One内部的two字段(无需修改原代码)

如果因为各种原因不能修改原业务代码,我们可以通过反射机制,把One内部私有的two字段替换成我们的Mock实例。

测试代码示例

import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.lang.reflect.Field;
import static org.mockito.Mockito.*;

public class OneTest {
    private One one;
    @Mock
    private Two mockTwo;

    @Before
    public void setup() {
        MockitoAnnotations.openMocks(this);
        one = new One();
        
        // 通过反射替换One内部的two字段
        try {
            Field twoField = One.class.getDeclaredField("two");
            twoField.setAccessible(true); // 允许访问私有字段
            twoField.set(one, mockTwo); // 替换为Mock实例
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testMethod1InClassOne() {
        doNothing().when(mockTwo).method3();
        
        one.method1();
        
        verify(mockTwo).method3();
    }
}

这样修改后,One内部调用的two.method3()就会是我们Mock的实例,模拟逻辑就能生效了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 07:42:29