Reputation: 22506
If java.net.URL
is used in a Spring Boot application, with classpath
protocol, it works as expected, because Spring Boot registers URLStreamHandlerFactory
. e.g. new URL("classpath: someFile.whatever")
.
But when this code is executed as JUnit test java.net.MalformedURLException: unknown protocol: classpath
exception is thrown.
It seems that the appropriate URLStreamHandlerFactory
is not registered when the Spring context is initialized for a JUnit test.
Steps to reproduce:
1) Create Spring Boot Starter project (e.g. using only starter Web).
2) add test.json
file in src/main/resources
3) Add the following bean:
@Component
public class MyComponent {
public MyComponent() throws MalformedURLException {
URL testJson = new URL("classpath: test.json");
System.out.println(testJson);
}
}
4) Starting the app as java application works OK
5) Run the default "contextLoads" test:
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringUrlTestApplicationTests {
@Test
public void contextLoads() {
}
}
java.net.MalformedURLException: unknown protocol: classpath
exception is thrown.
What is the appropriate way to use URL with classpath resources in JUnit test?
In the real use-case I cannot alter the new URL("classpath: test.json")
because it comes from 3th party library.
Tried to copy test.json
in src/test/resources
, to test if the error could be caused by a missing resource - no success.
Upvotes: 13
Views: 9269
Reputation: 902
The problem is that the class that is handling the protocol is org.apache.catalina.webresources.TomcatURLStreamHandlerFactory
. You can fix your test with this :
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MalformedUrlApplicationTests {
@Test
public void contextLoads() {
}
}
But i think @borino answer is better.
Upvotes: 1
Reputation: 613
Spring does not have a URLStreamHandler
that can process URLs for the "classpath:"
protocol. Spring handles this protocol with the ResourceLoader
API. Once you load a resource, you can get the URL for it.
However, Java provides a mechanism for supporting non-standard protocols. I found a StackOverflow entry which should answer your question.
Upvotes: 0
Reputation: 1750
the shortest and easiest way is to create simple method before test execution, which is creating and registering handlers for 'classpath' protocol.
@BeforeClass
public static void init() {
org.apache.catalina.webresources.TomcatURLStreamHandlerFactory.getInstance();
}
I just checked and it works fine. This approach also using inside of spring-boot applications
Upvotes: 19
Reputation: 836
I prefer the following way using apache commons:
String url = IOUtils.toString(
this.getClass().getResourceAsStream("test.json"),"UTF-8"
);
URL testJson = new URL(url);
File test.json => u can keep in src/test/resources folder -> it will be loaded from here, with maven it works for me
More methods like these are available here How to read a text-file resource into Java unit test?
Upvotes: 0
Reputation: 2939
I think you can try to Autowire the ResourceLoader, and load the file using resourceLoader.getResource("classpath:/test.json"), it will load the file from the resource folder.
Upvotes: 0