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

如何用Mockito模拟Random.nextDouble()测试依赖随机数的方法?

解决方案:模拟依赖随机数的方法

方法1:依赖注入Random实例(推荐)

核心思路是把Random从方法内部创建改为外部注入,让测试时能传入Mock对象。

修改业务代码:

public class YourService {
    private final Random random;

    // 构造函数注入Random实例
    public YourService(Random random) {
        this.random = random;
    }

    public String foo() {
        StringBuilder word = new StringBuilder();

        if (random.nextDouble() <= 0.5) {
            word.append("Hello");
        }
        if (random.nextDouble() <= 0.7) {
            word.append("World");
        }
        return word.toString();
    }
}

测试代码:

import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;

public class FooTest {
    @Test
    public void testFooReturnsWorld() {
        // Mock Random实例
        Random mockRandom = mock(Random.class);
        // 指定nextDouble的返回值
        when(mockRandom.nextDouble()).thenReturn(0.6);
        
        // 注入mock实例到业务类
        YourService service = new YourService(mockRandom);
        
        // 验证结果
        assertEquals("World", service.foo());
    }
}

方法2:用PowerMock拦截Random构造(无需修改业务代码)

如果无法改动原有业务代码,可以用PowerMock拦截new Random()的调用,强制返回Mock对象。

测试代码(需引入PowerMock依赖):

import org.junit.jupiter.api.Test;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.junit.runner.RunWith;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;

@RunWith(PowerMockRunner.class)
@PrepareForTest(YourService.class) // 指定要拦截构造逻辑的类
public class FooTest {
    @Test
    public void testFooReturnsWorld() throws Exception {
        // Mock Random实例
        Random mockRandom = mock(Random.class);
        when(mockRandom.nextDouble()).thenReturn(0.6);
        
        // 拦截new Random()调用,返回mock实例
        PowerMockito.whenNew(Random.class).withNoArguments().thenReturn(mockRandom);
        
        // 调用业务方法并验证
        YourService service = new YourService();
        assertEquals("World", service.foo());
    }
}

方法3:使用固定种子的Random(无需Mock)

Random使用固定种子时,生成的随机数序列是完全固定的,可利用这一点预测执行结果。

修改业务代码(新增测试用构造函数):

public class YourService {
    private Random random;

    public YourService() {
        this.random = new Random();
    }

    // 测试专用构造函数,传入固定种子
    public YourService(long seed) {
        this.random = new Random(seed);
    }

    public String foo() {
        StringBuilder word = new StringBuilder();

        if (random.nextDouble() <= 0.5) {
            word.append("Hello");
        }
        if (random.nextDouble() <= 0.7) {
            word.append("World");
        }
        return word.toString();
    }
}

测试代码:

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class FooTest {
    @Test
    public void testFooReturnsWorld() {
        // 提前找到符合条件的种子(比如1234),确保前两次nextDouble返回值满足判断逻辑
        YourService service = new YourService(1234L);
        assertEquals("World", service.foo());
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 20:40:44