Java - How to swap a resource file path for a test file during unit testing?

All singletons either eagerly or lazily instantiated are anti-pattern. Usage of singletons makes unit testing harder because there is no easy way to mock singleton.

Mock static method

A workaround is to use PowerMock to mock static method returning singleton instance.

Use dependency injection

A better solution is to use dependency injection. If you already use a dependency injection framework (e.g. Spring, CDI), refactor the code to make ResourceLoader a managed bean with scope singleton.

If you don't use a dependency injection framework, an easy refactoring will be to make changes to all classes using the singleton ResourceLoader:

public class MyService {

  public MyService() {
    this(ResourceLoader.getInstance());
  }

  public MyService(ResourceLoader resourceLoader) {
    this.resourceLoader = resourceLoader;
  }
}

And then in unit tests mock ResourceLoader using Mockito

ResourceLoader resourceLoader = mock(ResourceLoader.class);
when(ResourceLoader.getProperty("my-property")).thenReturn("10");
MyService myService = new MyService(resourceLoader);

Externalise configuration

Another approach is to place a file with test settings under src/test/resources. If you store settings in the src/main/resources/application.properties, a file src/test/resources/application.properties will override it.

Also, externalising configuration to a file not packaged in a JAR is a good idea. This way, file src/main/resources/application.properties will contain default properties and a file passed using command-line parameter will override these properties. So, a file with test properties will be passed as a command line parameter too. See how Spring handles externalised configuration.

Use Java System Properties

Even easier approach is to allow overriding of default properties with System Properties in the method ResourceLoader.getInstance().getProperty() and pass test properties this way

public String getProperty(String name) {
  // defaultProperties are loaded from a file on a file system:
  // defaultProperties.load(new FileInputStream(new File(filePath)));
  // or from a file in the classpath:
  // defaultProperties.load(ResourceLoader.class.getResourceAsStream(filePath));
  return System.getProperty(name, defaultProperties.get(name));
}