【发布时间】:2020-06-05 09:31:09
【问题描述】:
我正在尝试为 Spring Batch 应用程序编写 测试,特别是在获取记录时来自以下 reader 的交互来自实现简单 RowMapper 的数据库:
@Component
@StepScope
public class RecordItemReader extends JdbcCursorItemReader<FooDto> {
@Autowired
public RecordItemReader(DataSource dataSource) {
this.setDataSource(dataSource);
this.setSql(AN_SQL_QUERY);
this.setRowMapper(new RecordItemMapper());
}
}
这是批处理配置中的步骤定义:
@Bean
public Step step(RecordItemReader recordItemReader,
BatchSkipListener skipListener,
RecordItemWriter writer,
RecordItemProcessor processor,
PlatformTransactionManager transactionManager) {
return stepBuilderFactory
.get("step1")
.transactionManager(transactionManager)
.reader(recordItemReader)
.faultTolerant()
.skip(ParseException.class)
.skip(UnexpectedInputException.class)
.skipPolicy(new AlwaysSkipItemSkipPolicy())
.listener(skipListener)
.processor(processor)
.writer(writer)
.build();
}
一切正常,除非我尝试使用以下内容进行测试:
@SpringBatchTest
@EnableAutoConfiguration
class BatchSOTest extends Specification {
@Resource
JobLauncherTestUtils jobLauncherTestUtils
@Resource
JobRepositoryTestUtils jobRepositoryTestUtils
@Resource
RecordItemReader recordItemReader
def cleanup() {
jobRepositoryTestUtils.removeJobExecutions()
}
def "batch init perfectly"() {
given:
// this does not work :
(1.._) * recordItemReader.read() >> null
when:
def jobExecution = jobLauncherTestUtils.launchJob()
def jobInstance = jobExecution.getJobInstance()
def exitStatus = jobExecution.getExitStatus()
then:
jobInstance.getJobName() == "soJob"
exitStatus.getExitCode() == ExitStatus.SUCCESS.getExitCode()
}
}
我无法正确模拟阅读器,我尝试了各种方法,例如更新阅读器的属性,例如 MaxRows,但似乎没有任何效果。
更新阅读器结果的正确方法是什么?
或者是否需要以其他方式在单元测试期间正确地操作数据库中的记录?
更新:好的,所以我尝试了一种更结构化的方式,使用阅读器内部的服务:
@Component
public class FooDtoItemReader extends AbstractItemStreamItemReader<FooDto> {
private List<FooDto> foos ;
private final FooService fooService;
@Autowired
public FooDtoItemReader(FooService fooService) {
this.fooService = fooService;
}
@Override
public void open(ExecutionContext executionContext) {
try {
foos = fooService.getFoos();
...
public interface FooService {
List<FooDto> getFoos();
}
@Service
public class FooServiceImpl implements FooService {
@Autowired
private FooDao fooDao;
@Override
public List<FooDto> getFoos() {
return fooDao.getFoos();
}
}
@Repository
public class FooDaoImpl extends JdbcDaoSupport implements FooDao {
@Autowired
DataSource dataSource;
@PostConstruct
private void initialize() {
setDataSource(dataSource);
}
@Override
public List<FooDto> getFoos() {
return getJdbcTemplate().query(SELECT_SQL, new FooMapper());
}
}
在这里,我面临无法正确模拟我的服务的问题:
我一定是在测试工具中遗漏了一些东西。
class BatchSOTest extends Specification {
@Resource
JobLauncherTestUtils jobLauncherTestUtils
@Resource
JobRepositoryTestUtils jobRepositoryTestUtils
FooService fooService = Mock(FooService);
FooDtoItemReader fooDtoItemReader = new FooDtoItemReader(fooService)
def cleanup() {
jobRepositoryTestUtils.removeJobExecutions()
}
def "batch init perfectly (second version)"() {
given:
fooDtoItemReader.open(Mock(ExecutionContext))
and:
// still not working from there :
(1.._) * fooService.getFoos() >> [createFooEntity(123, "Test")]
when:
def jobExecution = jobLauncherTestUtils.launchJob()
def jobInstance = jobExecution.getJobInstance()
def exitStatus = jobExecution.getExitStatus()
then:
jobInstance.getJobName() == "soJob"
exitStatus.getExitCode() == ExitStatus.SUCCESS.getExitCode()
}
但如果我尝试从那里模拟,它会起作用:
class FooDtoItemReaderTest extends Specification {
FooService fooService = Mock(FooService);
FooDtoItemReader fooDtoItemReader = new FooDtoItemReader(fooService, 0)
def "open gets the foos and reader is initialized"() {
given: "Foos examples"
def foos = [
createFooEntity(123, "A"),
createFooEntity(456, "B")
]
when: "reader is initialized"
fooDtoItemReader.open(Mock(ExecutionContext))
then: "service get the expected foos"
1 * fooService.getFoos() >> foos
}
那我做错了什么?
【问题讨论】:
标签: java unit-testing groovy spring-batch spock