如何用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
相关产品推荐
相关产品推荐

