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

JUnit单元测试:Mockito.doNothing()模拟void方法未达预期

Mockito.doNothing() 模拟Void方法没生效?这几个坑你肯定踩了!

兄弟我懂你这种头疼的感觉——明明用了doNothing()想跳过那个会抛异常的functionC,结果测试还是崩在异常上,简直怀疑人生对吧?我来帮你捋捋最可能的几个原因,以及怎么解决。

首先,咱们先对齐一下你的场景:你要测试ClassA的functionA,这个方法会调用ClassB的void方法functionB,而functionB内部又会调用functionC(就是这个家伙会抛异常)。你本来想用doNothing()模拟functionB,让它啥也不干,这样就不会走到functionC了,但测试还是因为functionC的异常挂了。

最常见的坑:被测试类里用的不是Mock的ClassB实例

这绝对是80%的人会犯的错!比如你的ClassA是这么写的:

public class ClassA {
    public void functionA() {
        ClassB b = new ClassB(); // 这里直接new了真实的ClassB!
        b.functionB();
    }
}

不管你在测试里怎么mockClassB,ClassA里用的都是自己new出来的真实对象,那doNothing()自然完全没用,肯定会走到真实的functionB和functionC逻辑里。

解决办法:给ClassA注入ClassB的实例
你得让ClassA依赖的ClassB是外部传入的,比如用构造函数注入:

public class ClassA {
    private final ClassB classB;

    // 通过构造函数把ClassB传进来
    public ClassA(ClassB classB) {
        this.classB = classB;
    }

    public void functionA() {
        classB.functionB();
    }
}

这样在测试的时候,你就能把mock的ClassB传给ClassA,mock才会生效。

第二个坑:Mock的方法参数匹配不对

如果functionB是带参数的方法,比如void functionB(String id),而你mock的时候参数匹配错了,比如:

// 假设实际调用的是functionB("test123"),但你mock的是anyInt()
doNothing().when(mockClassB).functionB(anyInt());

这时候Mockito会认为你mock的是另一个方法(参数类型不对),所以还是会走真实的functionB方法,进而触发functionC的异常。

解决办法:确保参数匹配准确
要么用匹配器精准匹配:

// 匹配任意字符串
doNothing().when(mockClassB).functionB(anyString());
// 或者匹配具体值
doNothing().when(mockClassB).functionB(eq("test123"));

要么就完全和实际调用的参数一致。

第三个坑:误用了Mockito的语法

对于void方法,你不能用普通的when()语法,比如:

// 错误写法!调用mockClassB.functionB()会执行真实方法!
when(mockClassB.functionB()).doNothing();

因为when()里需要调用方法来捕获,但void方法调用后没有返回值,Mockito会直接执行真实的方法,那functionC自然会跑起来抛异常。

正确写法必须是前置doNothing():

doNothing().when(mockClassB).functionB();

这个语法才是告诉Mockito:当调用mock对象的functionB方法时,什么都不要做。

给你一个完整的正确示例

咱们把所有正确的代码拼起来,你对照着改:

被测试类ClassA(依赖注入版)

public class ClassA {
    private final ClassB classB;

    public ClassA(ClassB classB) {
        this.classB = classB;
    }

    public void functionA() {
        classB.functionB();
    }
}

ClassB的代码(包含会抛异常的functionC)

public class ClassB {
    public void functionB() {
        functionC();
    }

    private void functionC() {
        throw new RuntimeException("这个异常会搞砸测试");
    }
}

测试类(正确写法)

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.verify;

@RunWith(MockitoJUnitRunner.class)
public class ClassATest {

    @Mock
    private ClassB mockClassB;

    @Test
    public void testFunctionA() {
        // 把mock的ClassB传给ClassA
        ClassA classA = new ClassA(mockClassB);

        // 模拟void方法functionB,啥也不做
        doNothing().when(mockClassB).functionB();

        // 调用被测试方法
        classA.functionA();

        // 验证functionB确实被调用了
        verify(mockClassB).functionB();
        // 这时候functionC根本不会执行,测试顺利通过!
    }
}

最后总结一下关键要点

  1. 一定要保证被测试类使用的是你mock出来的实例,而不是自己new的真实对象;
  2. 针对void方法,必须用doNothing().when(mock).voidMethod()的语法;
  3. 检查方法参数的匹配是否正确,别让参数不匹配导致mock失效。

按照这个思路改,你的测试肯定能正常跑起来!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:11:43