Reputation: 349
newbie here! I found a lot of similar questions on SO, but none of them gave me a strait answer.
I wrote tests for all layers including the persistence layer in my spring-boot application. For testing the persistence layer I used H2 database. I used @DataJpaTest annotation and placed schema.sql and data.sql scripts to src/test/resources/db folder to create a schema and populate it with data from data.sql. And it works fine, all tests passing using that data.
Now what I am trying to do is to set up an integration test with @SpringBootTest to test whole application - top to bottom, from web layer to data layer. I made an application-test.properties with H2 config and annotated my test class with @ActiveProfiles("test") and it works fine. When I run this test class, application context fires up, H2 is up too, but of course, there is no data there. I would like to populate my in-memory database with the same date from data.sql from src/test/resources/db.
I modified application-test.properties in this way: spring.datasource.url=jdbc:h2:mem:testdb;INIT=RUNSCRIPT FROM 'classpath:db/schema.sql'\;RUNSCRIPT FROM 'classpath:db/data.sql' and I got org.h2.jdbc.JdbcSQLNonTransientException: IO Exception: "java.io.FileNotFoundException: resource /db/schema.sql" exception.
I have done a lot of googling and I found more resources saying src/main/resources and src/test/resources are both on the classpath. If so, why am I getting this exception?
Also, when I put those two scripts to src/main/resources/db it works fine. Also, it works fine when I run my persistence layer test no matter if those scripts are in src/main/resources/db or src/test/resources/db. So, it looks like a test environment using both src/main/resources and src/test/resources locations as classpath, but the environment uses only src/main/resources as classpath!? Could it be true?
One possible solution I tried and its works is not to run those scripts (removing INIT=RUNSCRIPT FROM 'classpath:db/schema.sql'\;RUNSCRIPT FROM 'classpath:db/data.sql' from .properties file) and before test programmatically create some object and persist them to database and then write test, but I think it is much easier and leaner to populate data from script than write this code in every test class.
Another possible solution is to copy those scripts from src/test/resources/db to src/main/resources/db, but it means I would have duplicated data and I hate that. Also, it means harder to maintaince.
The next possible solution is to put those scripts to src/main/resources/db because, as I said, data persistence test works fine no matter if those scripts are in src/main/resources/db or src/test/resources/db. But, those scripts are related to tests so I think they belong there not in the main part of the application.
And also, if I provide an absolute path to those scripts, it works fine, but it means my team members would have to modify it to fit their machines. Not really optimal solution.
So, my questions are: 1. Is it true that the test environment using both src/main/resources and src/test/resources locations as classpath, but the main environment uses only src/main/resources as classpath? 2. How can I resolve this challenge?
Upvotes: 4
Views: 5271
Reputation: 33441
Is it true that the test environment using both
src/main/resources
andsrc/test/resources
locations as classpath, but the main environment uses onlysrc/main/resources
as classpath?
Yes. It is true. In both Maven and Gradle test
classpath is inherited from main
and not vice versa. It means that classes and resources from src/main/java
and src/main/resources
are available during test execution, but src/test/java
and src/test/resources
are not reachable by the main codebase. Also note that test classes and resources are not transitive, i.e. they are not available in a depended projects.
How can I resolve this challenge?
Well, there are many solutions:
src/main
(obviously)Upvotes: 6