Java Mockito和Powermock无法模拟类加载器

Java Mockito和Powermock无法模拟类加载器,java,unit-testing,mockito,Java,Unit Testing,Mockito,我有以下Java指令: String path = MyClass.class.getClassLoader().getResource(fileName).getPath(); 我需要使用Mockito和Powermock模拟由MyClass.class.getClassLoader()返回的ClassLoader 我试过这个: @Mock ClassLoader classLoader; whenNew(ClassLoader.class).withAnyArguments().the

我有以下Java指令:

 String path = MyClass.class.getClassLoader().getResource(fileName).getPath();
我需要使用Mockito和Powermock模拟由
MyClass.class.getClassLoader()
返回的
ClassLoader

我试过这个:

@Mock ClassLoader classLoader;

whenNew(ClassLoader.class).withAnyArguments().thenReturn(classLoader);
但它不起作用


有人知道怎么做吗?

您正在模拟一个新语句,但代码中没有任何新语句

就我的理解而言,你应该:

  • 模拟静态MyClass
  • Mock getClassLoader()
  • 为类加载器创建一个模拟
  • 模拟方法getResource
具体如下:

@Mock ClassLoader classLoader;

    PowerMockito.mockStatic(MyClass.class);
    BDDMockito.given(MyClass.getClassLoader()).willReturn(classLoader);
    PowerMockito.doReturn("desiredResource").when(classLoader).getResource(Mockito.anyString());
此外,您可能需要在测试类开始时设置以下行:

@RunWith(PowerMockRunner.class)
@PowerMockListener(AnnotationEnabler.class)
@PrepareForTest({MyClass.class})
public class yourTestClass....

正如评论所指出的:你在错误的层次上接近这一点

查看您的代码:

String path = MyClass.class.getClassLoader().getResource(fileName).getPath();
你看,
MyClass.class.getClassLoader().getResource(文件名)
部分;这就是“内置”技术

我的意思是:除非代码中的其他部分与类加载器混在一起,否则上面的操作就是它应该做的。绝对没有必要对此进行广泛的测试。您只关心:这里的类和文件名;给我一条路这对你来说很重要。因此:抽象

换句话说:您只需继续并添加额外的抽象,如:

public interface PathProvider {
   public Path getPathFromUrl(Class<?> clazz);
}
公共接口路径提供程序{
公共路径getPathFromUrl(类clazz);
}
一个简单的实现可能看起来像

public class PathProviderImpl implements PathProvider {
   @Override
   Path getPathFromUrl(Class<?> clazz, String fileName) {
     return clazz.getClassLoader().getResource(fileName).getPath();
}
公共类PathProviderImpl实现PathProvider{
@凌驾
路径getPathFromUrl(类clazz,字符串文件名){
返回clazz.getClassLoader().getResource(文件名).getPath();
}
请注意:您也可以编写一个简单的单元测试来检查这个实现

但核心要点是:不要在生产代码中进行静态调用,而是使用该接口的(模拟)实例

不需要PowerMock,也不需要静态mock;只需要漂亮、简单的mockito东西


此外:上面的修复了您的设计问题。您创建了难以测试的生产代码;而您并不是使用大型PowerMock hammer来修复这一问题;而是改进了糟糕的设计。

“我需要模拟由…返回的类加载器。”不,你不需要。你需要改变你的设计。你会改变什么?这取决于你的代码做什么。但你可能会想引入一个额外的抽象级别。在最简单的情况下,通过一个接口引用你试图破解的类,并为此传递一个模拟。遵守,但这样我仍然需要对r访问类加载器的附加抽象级别。因此,问题没有改变,但是为了测试,PathProvider方法有两个参数,而它可能只有一个。这有什么错?它只是getPathFromUrl(字符串文件名)那么,这是否意味着为了测试,我正在使接口复杂化?这只是一个例子。当然,你可以改变所有事情,使IMPL类使用其构造函数使用文件名(或类),然后你不需要将其放入“接口”中方法。在这里不要期望完全正确的解决方案-这是为了激励您了解其他选项。答案并不意味着所有工作都完成了。相反;-)