Second datasource in spring application.properties for tests? - java

I have datasource defined in my application.properties as Oracle database and that's ok, the controller & repository work fine, I can persist entities and fetch database records.
I have integration tests written. Before I connected my app with database I created some objects and persisted them in #PostConstruct method - and that was ok. But now, when I connected everything with database, my tests try to fetch records from the table which is pretty large.
I think that's due to my application.properties file in which defined datasource is Oracle database.
spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:#blabla
spring.datasource.username=blabla
spring.datasource.password=blabla
spring.jpa.hibernate.ddl-auto=none
spring.jpa.generate-ddl=false
I want to carry on tests using some in-memory HSQL, not real database. But I still want my controller and repository to use the real one. How can I do it? Is there any possibility to add second datasource in application.properties? Or maybe an easier solution?

In Spring 4 you have #Profile annotation so you can use its advantage.
Create another like application-test.properties file with it's own properties.
Create configuration for your tests:
#Configuration
#Profile("test")
public class TestConfiguration {
....
}
Then annotate your class with #ActiveProfiles annotation:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = TestConfiguration.class)
#ActiveProfiles("test")
public class TestRepository {
...
}

There are many ways to achieve this, one way is to use Spring profiles. The test profile would use a different properties file than the production one.

Spring has org.springframework.mock.jndi.SimpleNamingContextBuilder package that allows you to bind the dataSource programatically.
Sample Test class that I use:
public class MockJNDIContext {
#BeforeClass
public static void setUpClass() throws Exception {
SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
OracleConnectionPoolDataSource ds = new OracleConnectionPoolDataSource();//Use your own Connection Pool DS here as you require
ds.setURL("jdbc:oracle:thin:#10.xxx.xxx.xx:9999:SID");
ds.setUser("USER");
ds.setPassword("PASSWORD");
//Bind it to the JNDI you need
builder.bind("java:comp/env/jdbc/MY/APP", ds);
}
#Test
public void test(){
System.out.println("JNDI Initialized");
}
}
Suite Class:
#RunWith(Suite.class)
#Suite.SuiteClasses({
MockJNDIContext.class,
InitializeTestConfig.class
})
public class ServiceSuite{
}
May be this helps? If you are trying to load from one more application.props, use one more class (InitializeTestConfig.class) that initializes and passes the DS args and add to suite as mentioned above and try?

Related

Testing spring boot api with database

I want auto testing my spring api. Now I have about 7-8 interesting situation and make:
deploy in postgres 7 db (test1, 2, ....)
application.properties write db test1.
run test and go to 2.
This is hard. What is easy way?
I want have one db for test (clear db, only tables structure)
before test write in db fixtures (special file with data, example - users, reports and other)
run test
after test delete fixture and have clear db again.
Can I do it by spring? Early I programming in python/django and use like way.
I think one way to solve that would be via custom properties files and #Configuration classes.
You would create for each Test the property file e.g. test1-dbA.properties
jdbc.driverClassName=org.h2.Driver
jdbc.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
jdbc.username=db1
jdbc.password=..
Next you would define the DataSource bean that loads the properties from the test1-dbA.properties
#Configuration
#EnableJpaRepositories(basePackages = "org.baeldung.repository")
#PropertySource("test1-dbA.properties")
#EnableTransactionManagement
public class DB1Config {
#Autowired
private Environment env;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.url"));
dataSource.setUsername(env.getProperty("jdbc.user"));
dataSource.setPassword(env.getProperty("jdbc.pass"));
return dataSource;
}
// ...
}
In the JUnit Test you would load the configuration class:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {Application.class, DB1Config.class})
public class db1Test{
// ...
}
This and other options can be looked up here: https://www.baeldung.com/spring-testing-separate-data-source and https://www.baeldung.com/spring-jpa-test-in-memory-database

Spring Batch JUnit test not loading application.properties for JobLauncherTestUtils

The problem rears its ugly head when the JdbcJobInstanceDao attempts to call the FIND_JOBS_WITH_KEY query:
SELECT JOB_INSTANCE_ID, JOB_NAME from %PREFIX%JOB_INSTANCE where JOB_NAME = ? and JOB_KEY = ?
the %PREFIX% token is replaced with the value of application.properties key spring.batch.table-prefix which defaults to "BATCH_".
The application properties are definitely loading from the files as my small test demonstrates:
#ActiveProfiles("test") // to load `application-test.properties`
#RunWith(SpringRunner.class)
// we don't need a web context as we are playing with only server side classes
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = {TestDatabaseConfig.class,
MyBatchProperties.class, SpringBatchTestConfig.class})
#ComponentScan(basePackageClasses = {MyBatchConfig.class})
// MyBatchConfig has #EnableBatchProcessing and all job configurations.
public class BatchTest {
#Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
#Autowired
private ApplicationContext applicationContext;
#Before
public void setup() {
Environment environment = applicationContext.getEnvironment();
System.out.println(environment.getProperty("spring.batch.table-prefix"));
// above prints MY_SCEHMA_USER.BATCH_ as expected
}
#Test
public void checkJobRuns() {
try {
jobLauncherTestUtils.launchJob();
} catch (Exception e) {
e.printStackTrace(); // <-- fails here with the query returning "table not found" because the prefix was not configured correctly.
}
}
}
application-test.properties:
spring.batch.table-prefix=MY_SCHEMA_USER.BATCH_
I've been working with custom configuration for job runs for a long time but the JobLauncherTestUtils doesn't seem to honour these configuration properties.
I need the different table prefix as the batch database tables are owned by a different schema to the connected database user. (i.e. MY_APP_USER trying to access MY_SCHEMA_USER.BATCH_JOB_INSTANCE). unqualified references to tables try (and fail) to resolve the batch tables against MY_APP_USER instead of MY_SCHEMA_USER.
I've tried to create a JobRepositoryFactoryBean bean and annotate it with #ConfigurationProperties("spring.batch"). However - along with this not working anyway - I don't see why I should configure these this way rather than with properties.
How to I get the Batch related beans properly configured with application properties in junit tests using JobLauncherTestUtils?
Fixed
The problem was because i was creating my own BatchConfigurer bean inside of the MyBatchConfig class.
The BatchConfigurer registers the properties for configuration with each component of the Batch framework (jobRepository, daos, etc...)
This meant that the properties were not being populated through the #Component annotated DefaultBatchConfigurer class. As to why I decided to place this piece of code in here even I - the author - Am not sure. I guess i need to not code after minimal sleep.
Thanks for indulging my stupidity!

Spring Boot remove #Component when unit testing

Bear with me as this is the first time I've used Spring Boot so this is only what I think is happening...
I have a couple of methods which are annotated with #Scheduled. They work great, and I have all of the dependencies configured and injected. These dependencies are quite heavy weight, relying on internet connections etc. I've annotated them as #Lazy, so they're only instantiated at the very last minute.
However, the classes which contain the scheduled methods need to be marked with #Component which means they're created on launch. This sets off a chain reaction which creates all of my dependencies whether I actually need them for the test I'm currently running.
When I run my unit tests on our CI server, they fail because the server isn't auth'd with the database (nor should it be).
The tests which test these #Scheduled jobs inject their own mocks, so they work fine. However, the tests which are completely unrelated are causing the problems as the classes are still created. I obviously don't want to create mocks in these tests for completely unrelated classes.
How can I prevent certain a #Component from being created when the tests are running?
Scheduled jobs class:
package example.scheduledtasks;
#Component
public class ScheduledJob {
private Database database;
#Autowired
public AccountsImporter(Database database) {
this.database = database;
}
#Scheduled(cron="0 0 04 * * *")
public void run() {
// Do something with the database
}
}
Config class:
package example
#Configuration
public class ApplicationConfig {
#Bean
#Lazy
public Database database() {
return ...;// Some heavy operation I don't want to do while testing.
}
}
I know you said:
I obviously don't want to create mocks in these tests for completely unrelated classes.
Still, just so you know, you can easily override the unwanted component just for this test:
#RunWith(...)
#Context...
public class YourTest {
public static class TestConfiguration {
#Bean
#Primary
public Database unwantedComponent(){
return Mockito.mock(Database.class);
}
}
#Test
public void yourTest(){
...
}
}
Similar question/answer: Override a single #Configuration class on every spring boot #Test
Just add the following to your test class:
#MockBean
public Database d;
Another alternative: use a in-memory database like h2 when testing. Create an application-test.properties with
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
See e.g. https://www.baeldung.com/spring-boot-h2-database .

UnitTests and Spring - create new beans?

I have an application where I use Spring (annotations, not xml), and I need to load the beans in my unit tests. I have the AppConfig class from my code which I want to use, but with a different datasource (one I define in the test folder). This is because I want to use an in memory DB in my tests, and not the real DB.
Here's how I try to run the AppConfig class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {App.class, AppConfig.class})
public class DAOManagerTest {
//All code goes here
#AutoWired
UserDAO userDAO;
#Test
public void testGet() {
List<User> test = userDAO.selectAll();
for (User u: test) {
u.toString();
}
}
}
This doesn't entirely work, as it fails on creating a bean inside the UserDAO class. I guess I need some tutorial / guide on how to deal with spring in unit tests. Should I define new beans in my test folder, or is it possible to user the spring class from my code? Also, is it possible to define a seperate datasource for the tests?
Yes. For example, if you define some beans in DAOManagerTest, using #Primary if necessary, and add DAOManagerTest.class to #ContextConfiguration.
There are so many other ways of arranging it though, like using profiles or mocks, etc.

Use Spring JpaRepository in test

I have Spring Boot application with configuration:
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled=true, prePostEnabled=true)
#EnableJpaRepositories(basePackages = "com.site.data.repository")
#EntityScan(basePackages = "com.site.data.entity")
#ComponentScan(basePackages = "com.*")
#SpringBootApplication
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
And in resources folder there is application.properties file:
spring.datasource.url=...
spring.datasource.username=...
spring.datasource.password=...
spring.datasource.driverClassName=...
#...
Problem:
I try to make new class which will add some entries to database. I thought that the best solution is making a JUnit test class. So if anybody wants to feed my database he could simply run this specific test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = WebSecurityConfig.class)
public class DataFeeder {
#Autowired
MyRepository myRepository;
#Test
public void feedDB() {
MyEntity entity = new MyEntity();
myRepository.saveAndFlush(entity);
}
}
But this configuration doesn't work. Of course all repositories work great in project. But during running test I obtain messages that all tables don't exist. For example for SOME_TABLE:
Table "SOME_TABLE" not found; SQL statement:
I saw a lot of tutorials about how to test JpaRepository, but I don't want make test, which add some items and delete it after test end. I simply want save some data in database (but in #Test function)
What is wrong with my configuration?
use #SpringApplicationConfiguration instead of #ContextConfiguration.
this is needed for Spring-boot application tests.

Categories