首页 > 解决方案 > 如何限制 Java ServiceLoader 仅加载测试包中定义的服务提供者

问题描述

我有一个使用 ServiceLoader 的应用程序。
有一个服务接口 MyFancyService 及其实现:AppClassA、AppClassB 和测试实现:TestClassC、TestClassD

应用包中有 META-INF.services,测试包中有另一个 META-INF.services。

应用程序中的 META-INF.services 指向提供程序类 AppClassA 和 AppClassB
测试点中的 META-INF.services 指向提供程序类 TestClassC 和 TestClassD

运行应用程序时,ServiceLoader.load(MyFancyService.class))仅加载AppClassA, AppClassB. 显然,类路径中没有测试类,这就是原因。我理解这一点,这是可取的

在运行测试时,ServiceLoader.load(MyFancyService.java)) 会加载所有类 AppClassA、AppClassB、TestClassC、TestClassD。

有没有办法限制服务加载器在运行测试时只TestClassC加载TestClassD

标签: javaunit-testingserviceloader

解决方案


当测试运行时,它在类路径中同时具有“测试”和“生产”类/资源。这就是加载所有四个服务的原因,这是一种理想的行为,您显然需要 test 和 prod 类路径。

因此,最重要的是,您有两个选择:

选项1

使用类似 PowerMock/PowerMockito 的工具来模拟静态方法ServiceLoader.load。我自己没有尝试过,但总的来说,除非它是某种遗留代码,否则我不建议使用它。

选项 2

重构代码并模拟对服务加载器的调用,如下所示:

inteface MyServiceLoader {
  void loadMyStuff(Class<?> type);
}

class MyServiceLoaderImpl implements MyServiceLoader {
   public void loadMyStuff(Class<?> type() {
       ServiceLoader.load(type);
   }
}


// and now in ClassUnderTest:

public class ClassUnderTest {

    private MyServiceLoader myServiceLoader;

    public void thisIsAMethodToTest() {
      ...
      myServiceLoader.loadMyStuff(MyFancyInterface.class); 
    }
}

在测试中,您可以使用 mockito 模拟接口MyServiceLoader.loadMyStuff并仅加载测试实现。


推荐阅读