View Javadoc
1   /*
2    * Copyright 2010-2025 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *    https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.mybatis.spring.batch.builder;
17  
18  import java.util.Arrays;
19  import java.util.Collections;
20  import java.util.HashMap;
21  import java.util.List;
22  import java.util.Map;
23  
24  import javax.sql.DataSource;
25  
26  import org.apache.ibatis.mapping.Environment;
27  import org.apache.ibatis.session.Configuration;
28  import org.apache.ibatis.session.ExecutorType;
29  import org.apache.ibatis.session.SqlSession;
30  import org.apache.ibatis.session.SqlSessionFactory;
31  import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
32  import org.assertj.core.api.Assertions;
33  import org.junit.jupiter.api.BeforeEach;
34  import org.junit.jupiter.api.Test;
35  import org.junit.jupiter.api.extension.ExtendWith;
36  import org.mockito.Mock;
37  import org.mockito.Mockito;
38  import org.mockito.junit.jupiter.MockitoExtension;
39  import org.mockito.junit.jupiter.MockitoSettings;
40  import org.mockito.quality.Strictness;
41  import org.springframework.batch.infrastructure.item.ExecutionContext;
42  
43  /**
44   * Tests for {@link MyBatisPagingItemReaderBuilder}.
45   *
46   * @since 2.0.0
47   *
48   * @author Kazuki Shimizu
49   */
50  @ExtendWith(MockitoExtension.class)
51  @MockitoSettings(strictness = Strictness.LENIENT)
52  class MyBatisPagingItemReaderBuilderTest {
53  
54    @Mock
55    private DataSource dataSource;
56  
57    @Mock
58    private SqlSessionFactory sqlSessionFactory;
59  
60    @Mock
61    private SqlSession sqlSession;
62  
63    @BeforeEach
64    void setUp() {
65      var configuration = new Configuration();
66      var environment = new Environment("unittest", new JdbcTransactionFactory(), dataSource);
67      configuration.setEnvironment(environment);
68      Mockito.when(this.sqlSessionFactory.getConfiguration()).thenReturn(configuration);
69      Mockito.when(this.sqlSessionFactory.openSession(ExecutorType.BATCH)).thenReturn(this.sqlSession);
70      Map<String, Object> parameters = new HashMap<>();
71      parameters.put("id", 1);
72      parameters.put("name", "Doe");
73      parameters.put("_page", 0);
74      parameters.put("_pagesize", 10);
75      parameters.put("_skiprows", 0);
76  
77      // Most tests are using this, lenient as a result on class.
78      Mockito.when(this.sqlSession.selectList("selectFoo", parameters)).thenReturn(getFoos());
79    }
80  
81    @Test
82    void testConfiguration() throws Exception {
83      // @formatter:off
84      var itemReader = new MyBatisPagingItemReaderBuilder<Foo>()
85              .sqlSessionFactory(this.sqlSessionFactory)
86              .queryId("selectFoo")
87              .parameterValues(Collections.singletonMap("id", 1))
88              .parameterValuesSupplier(() -> Collections.singletonMap("name", "Doe"))
89              .build();
90      // @formatter:on
91      itemReader.afterPropertiesSet();
92  
93      var executionContext = new ExecutionContext();
94      itemReader.open(executionContext);
95  
96      Assertions.assertThat(itemReader.read()).extracting(Foo::getName).isEqualTo("foo1");
97      Assertions.assertThat(itemReader.read()).extracting(Foo::getName).isEqualTo("foo2");
98      Assertions.assertThat(itemReader.read()).extracting(Foo::getName).isEqualTo("foo3");
99  
100     itemReader.update(executionContext);
101     Assertions.assertThat(executionContext.getInt("MyBatisPagingItemReader.read.count")).isEqualTo(3);
102     Assertions.assertThat(executionContext.containsKey("MyBatisPagingItemReader.read.count.max")).isFalse();
103 
104     Assertions.assertThat(itemReader.read()).isNull();
105   }
106 
107   @Test
108   void testConfigurationSaveStateIsFalse() throws Exception {
109     // @formatter:off
110     var itemReader = new MyBatisPagingItemReaderBuilder<Foo>()
111             .sqlSessionFactory(this.sqlSessionFactory)
112             .queryId("selectFoo")
113             .parameterValues(Collections.singletonMap("id", 1))
114             .parameterValuesSupplier(() -> Collections.singletonMap("name", "Doe"))
115             .saveState(false)
116             .build();
117     // @formatter:on
118     itemReader.afterPropertiesSet();
119 
120     var executionContext = new ExecutionContext();
121     itemReader.open(executionContext);
122 
123     Assertions.assertThat(itemReader.read()).extracting(Foo::getName).isEqualTo("foo1");
124     Assertions.assertThat(itemReader.read()).extracting(Foo::getName).isEqualTo("foo2");
125     Assertions.assertThat(itemReader.read()).extracting(Foo::getName).isEqualTo("foo3");
126 
127     itemReader.update(executionContext);
128     Assertions.assertThat(executionContext.isEmpty()).isTrue();
129   }
130 
131   @Test
132   void testConfigurationMaxItemCount() throws Exception {
133     // @formatter:off
134     var itemReader = new MyBatisPagingItemReaderBuilder<Foo>()
135             .sqlSessionFactory(this.sqlSessionFactory)
136             .queryId("selectFoo")
137             .parameterValues(Collections.singletonMap("id", 1))
138             .parameterValuesSupplier(() -> Collections.singletonMap("name", "Doe"))
139             .maxItemCount(2)
140             .build();
141     // @formatter:on
142     itemReader.afterPropertiesSet();
143 
144     var executionContext = new ExecutionContext();
145     itemReader.open(executionContext);
146 
147     Assertions.assertThat(itemReader.read()).extracting(Foo::getName).isEqualTo("foo1");
148     Assertions.assertThat(itemReader.read()).extracting(Foo::getName).isEqualTo("foo2");
149 
150     itemReader.update(executionContext);
151     Assertions.assertThat(executionContext.getInt("MyBatisPagingItemReader.read.count.max")).isEqualTo(2);
152 
153     Assertions.assertThat(itemReader.read()).isNull();
154   }
155 
156   @Test
157   void testConfigurationPageSize() throws Exception {
158     // @formatter:off
159     var itemReader = new MyBatisPagingItemReaderBuilder<Foo>()
160             .sqlSessionFactory(this.sqlSessionFactory)
161             .queryId("selectFoo")
162             .parameterValues(Collections.singletonMap("id", 1))
163             .parameterValuesSupplier(() -> Collections.singletonMap("name", "Doe"))
164             .pageSize(2)
165             .build();
166     // @formatter:on
167     itemReader.afterPropertiesSet();
168 
169     Map<String, Object> parameters = new HashMap<>();
170     parameters.put("id", 1);
171     parameters.put("_page", 0);
172     parameters.put("name", "Doe");
173     parameters.put("_pagesize", 2);
174     parameters.put("_skiprows", 0);
175 
176     // The initial mock on this needed repeated here, lenient as a result on class.
177     Mockito.when(this.sqlSession.selectList("selectFoo", parameters)).thenReturn(getFoos());
178 
179     var executionContext = new ExecutionContext();
180     itemReader.open(executionContext);
181 
182     Assertions.assertThat(itemReader.read()).extracting(Foo::getName).isEqualTo("foo1");
183     Assertions.assertThat(itemReader.read()).extracting(Foo::getName).isEqualTo("foo2");
184     Assertions.assertThat(itemReader.read()).isNull();
185   }
186 
187   private List<Object> getFoos() {
188     return Arrays.asList(new Foo("foo1"), new Foo("foo2"), new Foo("foo3"));
189   }
190 
191   private static class Foo {
192     private final String name;
193 
194     Foo(String name) {
195       this.name = name;
196     }
197 
198     public String getName() {
199       return this.name;
200     }
201   }
202 
203 }