4

I'm struggling to create a test to verify a ServletListener that loads a properties file. I've tested when running the application that it works fine and it finds the file in the classpath. But I don't know how to create a test for it. My idea is to create a temp file with a test property and then verify the property is put into the System properties. But I always fail to create the file in the right place.

I've tried creating the file in /target/test-classes or directly in the root of the application but it never finds it. Any idea?

This is the code I'm trying to test:

public class PropertyReadingListener implements ServletContextListener {

    public static final String PROFILES_PROPERTIES = "profiles.properties";

    @Override
    public void contextDestroyed(ServletContextEvent event) {
    }

    @Override
    public void contextInitialized(ServletContextEvent event) {
        Properties propsFromFile = new Properties();
        try {
            propsFromFile.load(getClass().getResourceAsStream(PROFILES_PROPERTIES));
        } catch (final Exception e) {
            log.warn("Unable to find {}, using default profile", PROFILES_PROPERTIES);
        }
        propsFromFile.stringPropertyNames().stream()
            .filter(prop -> System.getProperty(prop) == null)
            .forEach(prop -> System.setProperty(prop, propsFromFile.getProperty(prop)));
    }
}

Thanks.

Nicolas Filotto
  • 43,537
  • 11
  • 94
  • 122
Juan Vega
  • 1,030
  • 1
  • 16
  • 32
  • 1
    A good unit test will eliminate external dependencies (such as files) by mocking the behavior of collaborating classes. This is a good practice as it allows you to write a test that will run easily (i.e. you dont have to worry about deploying files or packaging your app in a JAR). – EJK Sep 09 '16 at 16:57
  • 1
    Are you building yor project with maven? Then you could put a test properties file to src/test/resources. This is then available only for test classes. You would load it with getResourceAsStream("/"+filename) – Jürgen Sep 09 '16 at 16:59

3 Answers3

1

Where is getResourceAsStream("file") searching when running from a test?

Assuming that you are talking about JUnit ....

Unless you have done something funky, your unit tests will be loaded by the default classloader, and that means that the normal JVM classpath with be searched.

(Junit 4 allows you to use a different classloader: see https://stackoverflow.com/a/9192126/139985)


But I always fail to create the file in the right place.

It seems that your real problem is understanding how the Java classpath and classpath searching works. If you understand that (and you know what JUnit runner's actual classpath is) then it should be obvious where to put the properties file so that the classloader can find it.

Graham
  • 7,431
  • 18
  • 59
  • 84
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • You are right, I didn't know exactly how it worked. I thought it was supposed to load from the classpath but I didn't know it depended on whether you use the class or the classloader to do it. – Juan Vega Sep 09 '16 at 17:44
1

Assuming that you are using maven, put your properties file here:

src/test/resources/foo.properties

The maven resources plugin will place the (possibly filtered) copy of the file in

target/test-classes/foo.properties

The test-classes directory is on the classpath, so you reference the file like this (note the slash in front of the file name):

... getResourceAsStream("/foo.properties");
Rob
  • 6,247
  • 2
  • 25
  • 33
0

See Different ways of loading a file as an InputStream

Basically when you do a getClass().getResourceAsStream it looks in the package of that class for the file.. so if your PropertyReadingListener is in com.company.listeners.PropertyReadingListener then it will look in com/company/listeners for the property file.

For testability, I would pass in an InputStream into the listener that way the test can create the input stream in a convienent way and the actual user of the class in code can pass in the InputStream returned from getResourceAsStream

Community
  • 1
  • 1
Brian Gorman
  • 794
  • 4
  • 8
  • Thanks for the link. That clarified the difference between using the class and the classloader to load the files. That basically was what I was failing to do, use the classloader. – Juan Vega Sep 09 '16 at 17:42
  • I tried so many things in the end I didn't try using "/" and the path with getClass().getResourceAsStream(). I have now tried both options and they work. – Juan Vega Sep 09 '16 at 17:49