How test UI elements / get ServiceLoader working?
In order to support pull request #8947 I want to make the casualty selection UI testable.
Calling UiContext.setDefaultMapDir from a new unit test causes a call to java.util.ServiceLoader for org.triplea.game.ApplicationContext.
This call fails.
This test will be interactive and is not meant to be included in a normal background test run. Is there a better context for my UI test code?
If not: What do I need to do so java.util.ServiceLoader successfully loads org.triplea.game.ApplicationContext.
Thanks in advance
@rainova I don't know if I'm fully clear on the goal. Is the goal to use Junit to launch a UI component? Could you do the same with a
It's been a while, so what I say may no longer be accurate, but I'm happy to try to help ...
Let me begin by saying, ideally, tests should never hit a
ServiceLoaderis a very simplistic DI framework that isn't really test-friendly because it doesn't allow programmatic registration of services. I'm pretty sure we originally strove to make all
main(because that method should have never been called from a test) and then injected the dependencies downstream from there using either constructor or setter injection.
With that being said, if you are hitting a
ServiceLoadercall from your test, it probably means a call to
ServiceLoaderwas added someplace outside of
main(possibly for good reasons at the time). My approach would be to identify where that
ServiceLoadercall is and either
- pull the dependency on
ApplicationContextupstream as far as you need and inject a test-specific
ApplicationContextfrom there via ctor/setter injection;
- if extracting the
ApplicationContextdependency is simply too complex, add a test-specific overload on the type in question, if possible, that allows your fixture to inject an
ApplicationContextbefore the test begins while leaving the default method in place for production code to continue to use;
- if the call site can handle no
ApplicationContextbeing available (unlikely but possible), replace the call to
Services#tryLoadAnyand deal with the
Optionalas needed; or
- if all else fails, you could try adding some helper methods to the
Servicesfacade (which all
ServiceLoadercalls should be going through) that allow you to programmatically register/unregister services during fixture setup/teardown; the complexity here is that
Servicesis just a collection of static methods and adding thread-safe state to it without converting it to a proper singleton is going to be less than satisfactory.
It would help to know the exact location where the problematic call to
ServiceLoaderis coming from. @RaiNova, could you identify that please? Given that your test is calling
UiContext#setDefaultMapDir, I'm guessing it may be
- pull the dependency on