【问题标题】:How to limit Java ServiceLoader to only load service providers defined in test packages如何限制 Java ServiceLoader 仅加载测试包中定义的服务提供者
【发布时间】:2019-11-14 10:25:39
【问题描述】:

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

【问题讨论】:

标签: java unit-testing serviceloader


【解决方案1】:

当测试运行时,它在类路径中同时具有“测试”和“生产”类/资源。 这就是加载所有四个服务的原因,这是一种理想的行为,您显然需要 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 并仅加载测试实现。

【讨论】:

  • 这是一个很好的答案,但我的 ServiceLoader.load 隐藏在自定义注释后面,并由一个解析注释的 Injector 类中的静态方法执行。在那种情况下很难嘲笑。也许我过度设计了一点。也许在测试中加载这些应用程序类并没有那么有害,即使它们的负载会很大。我想最终实现这样的目标:@ServiceLoad(MyFancyInterface::class) private lateinit var Iterable:
  • ServiceLoader 是一种非常“低级”的机制,不提供这种级别的自定义...
猜你喜欢
  • 2016-01-08
  • 2016-10-06
  • 2017-12-02
  • 1970-01-01
  • 1970-01-01
  • 2020-08-02
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
相关资源
最近更新 更多