在Java中,如何模拟使用ServiceLoader加载的服务?

Gra*_*oss 13 java mockito serviceloader

我有一个遗留Java应用程序,其代码类似于此

ServiceLoader.load(SomeInterface.class)
Run Code Online (Sandbox Code Playgroud)

我想为这段代码提供SomeInterface的模拟实现.我使用mockito模拟框架.

不幸的是我无法更改遗留代码,我不希望静态添加任何内容(例如,向META-INF添加内容).

在测试中是否有一种简单的方法可以做到这一点,即.在测试的运行时?

esa*_*saj 9

您可以将PowerMockito与Mockito一起使用来模拟静态方法:

@RunWith(PowerMockRunner.class)
@PrepareForTest(ServiceLoader.class)
public class PowerMockingStaticTest
{
    @Mock
    private ServiceLoader mockServiceLoader;

    @Before
    public void setUp()
    {
        PowerMockito.mockStatic(ServiceLoader.class);
        Mockito.when(ServiceLoader.load(Mockito.any(Class.class))).thenReturn(mockServiceLoader);
    }

    @Test
    public void test()
    {
        Assert.assertEquals(mockServiceLoader, ServiceLoader.load(Object.class));
    }
}
Run Code Online (Sandbox Code Playgroud)


Spa*_*ker 7

ServiceLoader.load文档:

使用当前线程的上下文类加载器为给定的服务类型创建新的服务加载器.

因此,您可以在测试运行期间使用特殊的上下文类加载器,以便动态生成提供程序配置文件META-INF/service.由于ServiceLoader文档中的这个注释,上下文类加载器将用于搜索提供者配置文件:

如果用于提供程序加载的类加载器的类路径包括远程网络URL,则在搜索提供程序配置文件的过程中将取消引用这些URL.

上下文类加载器还需要加载服务类的模拟实现,然后将其作为模拟实现传递.

这样的上下文类加载器需要做两件事:

  • 根据请求每个getResource*方法动态生成提供程序配置文件
  • 每个方法请求动态生成一个类(例如使用ASM库)loadClass,如果它是在动态生成的提供程序配置文件中指定的类

使用上述方法,您无需更改现有代码.