Mock Apache Commons Lang3的RandomStringUtils.random方法报错求助
问题:Mock Apache Commons Lang3 RandomStringUtils.random方法失败
问题场景
示例业务类
public class Example { public String generatePassword() { final String randomDevicePass = RandomStringUtils.random(10, "abcdefghijklmnopqrstuvwxyz"); System.out.println(randomDevicePass); return randomDevicePass; } }
测试类
@RunWith(MockitoJUnitRunner.class) public class ExampleTest { @InjectMocks private Example example; @Mock RandomStringUtils randomStringUtils; @Test public void givenCharacters_returnStringPassword() { Mockito.when(randomStringUtils.random(Mockito.anyInt(), Mockito.anyString())).thenReturn("asdf"); Assertions.assertEquals("asdf", example.generatePassword()); } }
错误信息
Misplaced or misused argument matcher detected here: You cannot use argument matchers outside of verification or stubbing. Examples of correct usage of argument matchers: when(mock.get(anyInt())).thenReturn(null); doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject()); verify(mock).someMethod(contains("foo")) This message may appear after an NullPointerException if the last matcher is returning an object like any() but the stubbed method signature expect a primitive argument, in this case, use primitive alternatives. when(mock.get(any())); // bad use, will raise NPE when(mock.get(anyInt())); // correct usage use Also, this error might show up because you use argument matchers with methods that cannot be mocked. Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode(). Mocking methods declared on non-public parent classes is not supported. org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Misplaced or misused argument matcher detected here:
原因分析
核心问题是:RandomStringUtils.random是静态方法,测试代码存在两个关键错误:
- 用
@Mock创建了RandomStringUtils的实例,但业务代码调用的是静态方法RandomStringUtils.random(...),完全不会用到这个实例,Mock无效。 - Mockito默认无法直接Mock静态方法,强行使用参数匹配器(
anyInt()/anyString())会触发参数匹配器误用错误。
解决方案
方案1:使用Mockito 3.4+的静态Mock功能
Mockito 3.4及以上版本支持直接Mock静态类,通过mockStatic方法创建静态Mock,配合try-with-resources确保测试后清理:
@RunWith(MockitoJUnitRunner.class) public class ExampleTest { private Example example = new Example(); @Test public void givenCharacters_returnStringPassword() { try (MockedStatic<RandomStringUtils> mockedStatic = Mockito.mockStatic(RandomStringUtils.class)) { mockedStatic.when(() -> RandomStringUtils.random(10, "abcdefghijklmnopqrstuvwxyz")) .thenReturn("asdf"); Assertions.assertEquals("asdf", example.generatePassword()); } } }
方案2:封装静态调用(推荐,符合依赖注入原则)
把静态方法调用封装成可注入的服务类,解耦静态依赖,提升代码可测试性:
- 创建封装类
public class PasswordGenerator { public String generateRandomString(int length, String chars) { return RandomStringUtils.random(length, chars); } }
- 修改业务类,注入封装类
public class Example { private final PasswordGenerator passwordGenerator; // 构造注入,测试时可传入Mock实例 public Example(PasswordGenerator passwordGenerator) { this.passwordGenerator = passwordGenerator; } public String generatePassword() { final String randomDevicePass = passwordGenerator.generateRandomString(10, "abcdefghijklmnopqrstuvwxyz"); System.out.println(randomDevicePass); return randomDevicePass; } }
- 测试类Mock封装类
@RunWith(MockitoJUnitRunner.class) public class ExampleTest { @InjectMocks private Example example; @Mock private PasswordGenerator passwordGenerator; @Test public void givenCharacters_returnStringPassword() { Mockito.when(passwordGenerator.generateRandomString(10, "abcdefghijklmnopqrstuvwxyz")) .thenReturn("asdf"); Assertions.assertEquals("asdf", example.generatePassword()); } }
方案3:使用PowerMock(不推荐)
如果使用旧版本Mockito,可通过PowerMock实现静态Mock,但PowerMock会修改类加载器,增加测试复杂度:
@RunWith(PowerMockRunner.class) @PrepareForTest(RandomStringUtils.class) public class ExampleTest { private Example example = new Example(); @Test public void givenCharacters_returnStringPassword() { PowerMockito.mockStatic(RandomStringUtils.class); Mockito.when(RandomStringUtils.random(10, "abcdefghijklmnopqrstuvwxyz")) .thenReturn("asdf"); Assertions.assertEquals("asdf", example.generatePassword()); } }
总结
优先选择封装静态调用的方案,它不仅解决测试问题,还提升了代码的可维护性和扩展性;若不想修改业务代码,可使用Mockito自带的静态Mock功能;尽量避免使用PowerMock,除非有特殊历史原因。
内容的提问来源于stack exchange,提问作者EV Experience
相关产品推荐
相关产品推荐

