javajunitclassloader

Why my unit test cant read file from src/test/resources in unit tests?


I have this method in a utility class in the path src/main/java/packege/Myclass.java:

public static void dummymethod(String file1, String file2) {
     ….
        try (InputStream xsdStream = XMLValidator.class.getClassLoader().getResourceAsStream(file1)) {
           // do something with file2
           ….
        }
    }….
}

This method reads files from src/main/resources on runtime. However I have now written this unit test and it still attempts to read the files from src/main/resources although I would like it to read the resources from src/test/resources since my utility test is in the path src/test/java/util/mytestclass.class:

public class MyLoginTest {
    @Test
    void testValidfie() {
        String path1 = “file.json”;
        String path2 = “file2.json”;

        dummymethod(path1, path2);

        assertTrue(true);
    }

My unit test cannot find the files located in src/test/resources and still reads files from src/main/resources.

This is the program structure:

my-project
├── src
│   ├── main
│   │   ├── java
│   │   │   └── package
│   │   │       └── Myclass.java          // Contains dummymethod
│   │   └── resources
│   │       ├── file.json                  // Resource for production code
│   │       └── file2.json                 // Another resource for production code
│   └── test
│       ├── java
│       │   └── util
│       │       ├── MyLoginTest.java      // Contains testValidFile
│       │       └── OtherTest.java        // Additional tests if needed
│       └── resources
│           ├── file.json                  // Test resource
│           └── file2.json                 // Another test resource

Does anyone understand why this is the case?


Solution

  • The getResourceAsStream method relies on the classpath to locate resources, and the test classpath typically includes both src/main/resources and src/test/resources. However, resources in src/main/resources may take precedence over those in src/test/resources if they have the same name.

    Additionally, when you pass a filename like "file.json" without specifying a directory, it tries to find the resource from the default classpath, which could be in src/main/resources.

    You should consider creating a method that accepts a classloader as a parameter and call that in your test using the test's classloader and not the XMLValidator's classloader.

    public static void dummymethod(String file1, String file2, ClassLoader classLoader){
        try (InputStream xsdStream = classLoader.getResourceAsStream(file1)) {
            // do something with file2
            // ...
        }
    }
    
    public class MyLoginTest {
        @Test
        void testValidfie() {
            String path1 = "file.json";
            String path2 = "file2.json";
            
            // Use the test class loader to load resources from src/test/resources
            dummymethod(path1, path2, this.getClass().getClassLoader());
            
            assertTrue(true);
        }
    }
    

    Alternative: Be more explicit with the location of your resrouce

    public class MyLoginTest {
        @Test
        void testValidfie() {
            String path1 = "test_resources/file.json"; // Adjust the path as necessary
            String path2 = "test_resources/file2.json";
            
            dummymethod(path1, path2);
            
            assertTrue(true);
        }
    }