How can I mock the presence of a properties file on the classpath?

为君一笑 提交于 2019-12-23 09:37:37

问题


This surely is a common problem. I have a properties file like my-settings.properties which is read by an application class. When I write a test class, it needs to test different scenarios of things that could be present in my-settings.properties in order to ensure maximum code coverage (e.g. empty properties file, basic properties file etc). But I can only have one my-settings.properties in my src/test/resources.

What would be really great is if there was just some annotation

@MockFileOnClassPath(use = "my-settings-basic.properties", insteadOf = "my-settings.properties")

Then I could just have multiple my-settings-XXX.properties files in my /src/test/resources and just annotated the correct one on each test method. But I can't find anything like this. I'm using JUnit 4.12.

I can think of a couple of crude solutions:

  1. Before each test, find the file on the file system, copy it using filesystem I/O, then delete it again after the test. But this is clumsy and involves a lot of redundancy. Not to mention I'm not even sure whether the classpath directory will be writable.
  2. Use a mocking framework to mock getResource. No idea how I would even do that, especially as there are a million different ways to get the file (this.getClass().getResourceAsStream(...), MyClass.class.getResourceAsStream(...), ClassLoader.getSystemClassLoader().getResourceAsStream(...) etc.)

I just think this must be a common problem and maybe there is already a solution in JUnit, Mockito, PowerMock, EasyMock or something like that?

EDIT: Someone has specified that this question is a duplicate of Specifying a custom log4j.properties file for all of JUnit tests run from Eclipse but it isn't. That question is about wanting to have a different properties file between the main and test invocations. For me I want to have a different properties file between a test invocation and another test invocation.


回答1:


I find that whenever dealing with files, it's best to introduce the concept of a Resource.

eg:

public interface Resource {
    String getName();
    InputStream getStream();
}

Then you can pass the resource in via dependency injection:

public class MyService {
    private final Properties properties;

    public class MyService(Resource propFile) {
        this.properties = new Properties();
        this.properties.load(propFile.getStream());
    }

    ...
}

Then, in your production code you can use a ClasspathResource or maybe a FileResource or URLResource etc but in your tests you could have a StringResource etc.

Note, if you use spring you already have an implenentation of this concept. More details here




回答2:


You can change your Service class to accept the name of the resource file, then then use that name to load the resource.

public class MyService {

 public MyService(String resourceFileName){
   //and load it into Properties  getResourceAsStream(resourceFileName);
 }
}


来源:https://stackoverflow.com/questions/32826119/how-can-i-mock-the-presence-of-a-properties-file-on-the-classpath

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!