32

I'm trying to read a file from classpath like this in my unit test:

@Value("classpath:state.json")
Resource stateFile;

I have state.json file in src/test/resources directory. When I try to read this file using stateFile.getInputStream(), it doesn't return any contents. What am I doing wrong?

My test class is annotated like this

@RunWith(SpringRunner.class)
@SpringBootTest

I can see that the code fails if I try with a incorrect file. So I think its seeing the file in classpath but for some reason not reading contents.

Nithin Satheesan
  • 1,546
  • 3
  • 17
  • 30

4 Answers4

19

I just ran into this. I'm using Maven. I took a look at my target/test-classes folder and my resource file wasn't in there (even though it was in my src/test/resources folder).

I ran mvn clean install and then rechecked my target/test-classes folder and the resource file was now there. After that, my test was able to find the file and the test worked.

So it seems that your resources aren't copied until you do a mvn clean. JUnit is looking in the classpath built by maven and until the file actually makes it into the target/test-classes folder, JUnit won't be able to find it.

Collin Krawll
  • 2,210
  • 17
  • 15
15

You cant access a @Value resource unless its a property defined. It should be this way.

@Value("${stateJsonPath}")
Resource stateFile;

If you have to get the resource from hardcoded path then use this way.

Resource stateFile = new ClassPathResource("state.json");
Praneeth Ramesh
  • 3,434
  • 1
  • 28
  • 34
  • 3
    What Resource class is this? There's like 5. – G_V Oct 17 '19 at 15:14
  • Probably `org.springframework.core.io.ClassPathResource` – Conrad Feb 23 '21 at 13:40
  • 3
    This answer is wrong. Mandatory usage of a "property" (a SpEL reference to Spring's Environment) in `@Value` makes no sense. The OP's code `@Value("classpath:state.json") Resource stateFile` is perfectly valid. – Peter Wippermann Jul 01 '22 at 13:48
6

Sharing the working solution for posterity. Files present in the classpath can be read using org.springframework.core.io.ResourceLoader. For instance, I have a sample data file called posts.json under directory src/test/java/resources/data and I have to load it during the test case execution as part of @Before

@ActiveProfiles("test")
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SampleTest {

    @Autowired
    private ResourceLoader resourceLoader = null;

    @BeforeEach
    void init() {
        File dataFile = resourceLoader.getResource("classpath:data/posts.json").getFile();
        ...
        ...
    }

}

NOTE: the file should present in the classpath when you use the classifier classpath:

Prasanth Rajendran
  • 4,570
  • 2
  • 42
  • 59
5

This should simply work, notice that the path starts with a dot, indicating current directory;

@Test   
public void testFile() {
    String path = "./src/test/resources";
    String fileName = "test.zip";

    File file = new File(path, fileName);

    assertTrue(file.exists());
}
Levent Divilioglu
  • 11,198
  • 5
  • 59
  • 106
  • The OP asked for reading a file from the Classpath and want's to use Spring's Dependency Injection. – Peter Wippermann Jul 01 '22 at 13:51
  • @PeterWippermann Right, but the title does not have a consistency with the content of the question then. If title of the questions are not particular and clear, then SO will be full of duplicate questions with same/similar titles and different question content. My answer is an example of reading file to the question title. – Levent Divilioglu Jan 05 '23 at 12:01
  • I thought I got your point, but the title mentions _Spring Boot:_ explicitly!? Anyway, if the title doesn't match the question, I'd propose you edit the title so future readers can benefit :-) Will also reduce the number of duplicates, I think. – Peter Wippermann Jan 06 '23 at 14:10