如何将Java ServiceLoader限制为仅加载测试包中定义的服务提供程序

如何将Java ServiceLoader限制为仅加载测试包中定义的服务提供程序,java,unit-testing,serviceloader,Java,Unit Testing,Serviceloader,我有一个使用ServiceLoader的应用程序。 有一个服务接口MyFancyService及其实现:AppClassA、AppClassB和测试实现:TestClassC、TestClassD 应用程序包中有META-INF.services,测试包中有另一个META-INF.services。 应用程序中的META-INF.services指向提供程序类AppClassA和 测试点到提供程序类中的AppClassBMETA-INF.services TestClassC和TestClass

我有一个使用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

当测试运行时,类路径中同时包含“测试”和“生产”类/资源。 这就是为什么要加载所有四个服务,这是一个理想的行为,您显然需要测试和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); 
    }
}

inteface MyServiceLoader{
void loadMyStuff(类类型);
}
类MyServiceLoaderImpl实现MyServiceLoader{
公共void loadMyStuff(类类型(){
ServiceLoader.load(类型);
}
}
//现在在ClassUnderTest中:
公共类未测试{
私有MyServiceLoader MyServiceLoader;
公共无效ThisisMethodToTest(){
...
loadMyStuff(MyFancyInterface.class);
}
}

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

通常测试文件测试应用程序类,没有应用程序,您将测试什么?更新:在编写答案后,我发现以下线程:这是一个非常好的答案,但我的ServiceLoader.load隐藏在cu后面stom注释并在一个Injector类中通过静态方法执行,该类解析注释。在这种情况下很难模拟。也许我设计得有点过头了。也许在测试中加载这些应用程序类并没有那么有害,即使它们的负载将是巨大的。我希望最终实现类似的目标:@ServiceLoad(MyFancyInterface::class)私有lateinit变量Iterable:ServiceLoader是一种非常“低级”的机制,不提供这样的自定义级别。。。