I'm trying to build an end-to-end test on a spring-batch project, however, when trying to run the execution of a single step, the database appears to be not initialized. The contextLoads
test runs okay, and the individual test of custom itemReader also work okay, so I assume there is something missing on the configuration of spring batch itself, but can't figure out what.
Application:
@EnableTransactionManagement
@SpringBootApplication
public class DadosSegurancaApplication {
public static void main(String[] args) {
SpringApplication.run(DadosSegurancaApplication.class, args);
}
}
Job Config
@Configuration
public class JobConfigs extends DefaultBatchConfiguration {
...
@Bean
public Step loadSubtractedObjectToDbStep(JobRepository jobRepository, PlatformTransactionManager transactionManager, ExcelReader excelReader, RepositoryItemWriter<SubtractedObject> subtractedObjectItemWriter) {
return new StepBuilder("loadSubtractedObjectToDbStep", jobRepository)
.<SubtractedObject, SubtractedObject>chunk(ROWS_PER_CHUNK, transactionManager)
.reader(excelReader)
.writer(subtractedObjectItemWriter)
.build();
}
@Bean
public Job subtractedObjectsJob(JobRepository jobRepository, Step loadSubtractedObjectToDbStep) {
return new JobBuilder("subtractedObjectsJob", jobRepository)
.start(loadSubtractedObjectToDbStep)
.build();
}
...
}
Application properties:
spring.datasource.url=jdbc:h2:file:./local.db
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update
spring.batch.initialize-schema=always
Test
@SpringJUnitConfig
@SpringBatchTest
@SpringBootTest(classes = { DadosSegurancaApplication.class })
public class SubtractedObjectExcelStepTest {
@Autowired
private ExcelReader reader;
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
@Autowired
private Job subtractedObjectsJob;
@Test // FAILS WITH ERROR BELLOW
public void executeSingleStep() {
jobLauncherTestUtils.setJob(subtractedObjectsJob);
jobLauncherTestUtils.launchStep("loadSubtractedObjectToDbStep");
}
@Test // WORKS
public void testAllReads() throws Exception {
assertSingle(reader.read(), "READ");
assertSingle(reader.read(), "READ2");
assertSingle(reader.read(), "READ3");
Assertions.assertNull(reader.read());
}
}
Stack trace:
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [SELECT JOB_INSTANCE_ID, JOB_NAME
FROM BATCH_JOB_INSTANCE
WHERE JOB_NAME = ?
and JOB_KEY = ?]
at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:103)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:107)
at org.springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1548)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:677)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:723)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:754)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:767)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:825)
at org.springframework.batch.core.repository.dao.JdbcJobInstanceDao.getJobInstance(JdbcJobInstanceDao.java:183)
at org.springframework.batch.core.repository.support.SimpleJobRepository.getLastJobExecution(SimpleJobRepository.java:299)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:355)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:379)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:223)
at jdk.proxy2/jdk.proxy2.$Proxy102.getLastJobExecution(Unknown Source)
at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:111)
at org.springframework.batch.core.launch.support.TaskExecutorJobLauncher.run(TaskExecutorJobLauncher.java:59)
at org.springframework.batch.test.StepRunner.launchJob(StepRunner.java:175)
at org.springframework.batch.test.StepRunner.launchStep(StepRunner.java:165)
at org.springframework.batch.test.JobLauncherTestUtils.launchStep(JobLauncherTestUtils.java:241)
at org.springframework.batch.test.JobLauncherTestUtils.launchStep(JobLauncherTestUtils.java:188)
at unit.SubtractedObjectExcelStepTest.executeSingleStep(SubtractedObjectExcelStepTest.java:56)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "BATCH_JOB_INSTANCE" not found; SQL statement:
SELECT JOB_INSTANCE_ID, JOB_NAME
FROM BATCH_JOB_INSTANCE
WHERE JOB_NAME = ?
and JOB_KEY = ? [42102-224]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:514)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:489)
at org.h2.message.DbException.get(DbException.java:223)
at org.h2.message.DbException.get(DbException.java:199)
at org.h2.command.Parser.getTableOrViewNotFoundDbException(Parser.java:8064)
at org.h2.command.Parser.getTableOrViewNotFoundDbException(Parser.java:8035)
at org.h2.command.Parser.readTableOrView(Parser.java:8024)
at org.h2.command.Parser.readTablePrimary(Parser.java:1788)
at org.h2.command.Parser.readTableReference(Parser.java:2268)
at org.h2.command.Parser.parseSelectFromPart(Parser.java:2718)
at org.h2.command.Parser.parseSelect(Parser.java:2824)
at org.h2.command.Parser.parseQueryPrimary(Parser.java:2708)
at org.h2.command.Parser.parseQueryTerm(Parser.java:2564)
at org.h2.command.Parser.parseQueryExpressionBody(Parser.java:2543)
at org.h2.command.Parser.parseQueryExpressionBodyAndEndOfQuery(Parser.java:2536)
at org.h2.command.Parser.parseQueryExpression(Parser.java:2529)
at org.h2.command.Parser.parseQuery(Parser.java:2498)
at org.h2.command.Parser.parsePrepared(Parser.java:627)
at org.h2.command.Parser.parse(Parser.java:592)
at org.h2.command.Parser.parse(Parser.java:564)
at org.h2.command.Parser.prepareCommand(Parser.java:483)
at org.h2.engine.SessionLocal.prepareLocal(SessionLocal.java:639)
at org.h2.engine.SessionLocal.prepareCommand(SessionLocal.java:559)
at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1166)
at org.h2.jdbc.JdbcPreparedStatement.<init>(JdbcPreparedStatement.java:93)
at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:316)
at com.zaxxer.hikari.pool.ProxyConnection.prepareStatement(ProxyConnection.java:328)
at com.zaxxer.hikari.pool.HikariProxyConnection.prepareStatement(HikariProxyConnection.java)
at org.springframework.jdbc.core.JdbcTemplate$SimplePreparedStatementCreator.createPreparedStatement(JdbcTemplate.java:1711)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:656)
... 28 more
Any thoughts on the why even though the application starts and configures okay, the tables in the database are not initialized?
This is because your configuration class extends DefaultBatchConfiguration
, which makes the auto-configuration of Spring Boot to back-off (see this note). Therefore, you need to initialize the database with batch tables yourself.
It is also necessary to use the correct configuration to enable the batch database setup with spring.batch.jdbc.initialize-schema=always