I am testing @stepscope JDBCCUrsorIteamReader but getting below error. I am opening the reader before start reading but still its giving reader is not opened. I want to mock database calls.
How can i make it work while mocking the DB calls
org.springframework.batch.item.ReaderNotOpenException: Reader must be open before it can be read.
reader code
@Bean
@StepScope
public JdbcCursorItemReader<LimsExternalLinkDTO> findExternalLinksReader(@Value("#{jobParameters['bookId'] != null ? jobParameters['bookId'] : 0}") int bookId) {
JdbcCursorItemReader<LimsExternalLinkDTO> reader = new JdbcCursorItemReader<>();
reader.setDataSource(dataSource);
reader.setSql(FIND_EXTERNAL_LINKS);
reader.setPreparedStatementSetter(ps -> {
ps.setInt(1, bookId);
ps.setInt(2, bookId);
});
reader.setRowMapper(new BeanPropertyRowMapper<>(LimsExternalLinkDTO.class));
reader.setFetchSize(BATCH_SIZE);
reader.setQueryTimeout(REQUEST_TIMEOUT);
return reader;
}
Reader Test code
@ContextConfiguration
@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class,
StepScopeTestExecutionListener.class })
@RunWith(SpringJUnit4ClassRunner.class)
class ReaderConfigurationTest {
@Autowired
private JdbcCursorItemReader<LimsExternalLinkDTO> itemReader;
@BeforeEach
void setUp() throws SQLException {
itemReader = new JdbcCursorItemReader<>();
// itemReader.setDataSource(ds);
}
@AfterEach
void tearDown() {
}
@Test
void testUsesCurrentTransaction() throws Exception {
DataSource ds = Mockito.mock(DataSource.class);
Connection con = Mockito.mock(Connection.class);
Mockito.when(con.getAutoCommit()).thenReturn(false);
PreparedStatement ps = Mockito.mock(PreparedStatement.class);
Mockito.when(con.prepareStatement("select foo from bar", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
ResultSet.HOLD_CURSORS_OVER_COMMIT))
.thenReturn(ps);
Mockito.when(ds.getConnection()).thenReturn(con);
Mockito.when(ds.getConnection()).thenReturn(con);
con.commit();
PlatformTransactionManager tm = new JdbcTransactionManager(ds);
TransactionTemplate tt = new TransactionTemplate(tm);
final JdbcCursorItemReader<LimsExternalLinkDTO> reader = new JdbcCursorItemReader<>();
reader.setDataSource(new ExtendedConnectionDataSourceProxy(ds));
reader.setUseSharedExtendedConnection(true);
reader.setSql("select foo from bar");
final ExecutionContext ec = new ExecutionContext();
ec.put("externalLinks",mockedLimsExternalLinkData());
tt.execute(status -> {
reader.open(ec);
try {
reader.read();
} catch (Exception e) {
throw new RuntimeException(e);
}
reader.close();
return null;
});
}
public List<LimsExternalLinkDTO> mockedLimsExternalLinkData() {
List<LimsExternalLinkDTO> linksList = new ArrayList<>();
LimsExternalLinkDTO limsExternalLink = new LimsExternalLinkDTO();
limsExternalLink.setExternalLink("https://www.google.com");
limsExternalLink.setId(1);
limsExternalLink.setBookName("Test Book");
limsExternalLink.setStatus(null);
limsExternalLink.setBookId(316);
limsExternalLink.setChapterId(6);
limsExternalLink.setChapterName("Abacavir");
limsExternalLink.setSectionId(1);
limsExternalLink.setSectionName("Section1");
limsExternalLink.setFieldId(1);
linksList.add(limsExternalLink);
return linksList;
}
}
logs-
11:23:07.607 [Test worker] DEBUG org.springframework.jdbc.support.JdbcTransactionManager - Creating new transaction with name [null]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
11:23:07.613 [Test worker] DEBUG org.springframework.jdbc.support.JdbcTransactionManager - Acquired Connection [Mock for Connection, hashCode: 718512571] for JDBC transaction
11:23:07.617 [Test worker] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
11:23:07.630 [Test worker] DEBUG org.springframework.transaction.support.TransactionTemplate - Initiating transaction rollback on application exception
java.lang.RuntimeException: org.springframework.batch.item.ReaderNotOpenException: Reader must be open before it can be read.
at com.lexi.lims.reports.externallinks.batch.reader.ReaderConfigurationTest.lambda$testUsesCurrentTransaction$0(ReaderConfigurationTest.java:89)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
at com.lexi.lims.reports.externallinks.batch.reader.ReaderConfigurationTest.testUsesCurrentTransaction(ReaderConfigurationTest.java:83)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.util.ArrayList.forEach(ArrayList.java:1259)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.util.ArrayList.forEach(ArrayList.java:1259)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at com.sun.proxy.$Proxy2.stop(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:133)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:71)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
Caused by: org.springframework.batch.item.ReaderNotOpenException: Reader must be open before it can be read.
at org.springframework.batch.item.database.AbstractCursorItemReader.doRead(AbstractCursorItemReader.java:497)
at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.read(AbstractItemCountingItemStreamItemReader.java:93)
at com.lexi.lims.reports.externallinks.batch.reader.ReaderConfigurationTest.lambda$testUsesCurrentTransaction$0(ReaderConfigurationTest.java:87)
... 85 common frames omitted
11:23:07.637 [Test worker] DEBUG org.springframework.jdbc.support.JdbcTransactionManager - Initiating transaction rollback
11:23:07.638 [Test worker] DEBUG org.springframework.jdbc.support.JdbcTransactionManager - Rolling back JDBC transaction on Connection [Mock for Connection, hashCode: 718512571]
11:23:07.638 [Test worker] DEBUG org.springframework.jdbc.support.JdbcTransactionManager - Releasing JDBC Connection [Mock for Connection, hashCode: 718512571] after transaction
The code you shared autowires the
JdbcCursorItemReaderin the test class (this means the reader should be defined as a bean in the test context and managed by Spring), and at the same time creates the bean manually in thesetUpmethod. This is incorrect, the manual creation of the bean should be removed.The example of testing scoped beans in the reference documentation does not create the bean manually with the
newoperator: Testing Step-Scoped Components.That said, the error you have seems to happen before the test is called where the reader is indeed opened before starting to read data.