如何使用Spock和Groovy在Spring Batch应用程序中模拟ItemReader

问题描述 投票:0回答:1

我正在尝试为Spring Batch应用程序编写tests,特别是关于以下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,但似乎无济于事。

什么是更新阅读器结果的正确方法?>

或者是否需要采取另一种方式从数据库在单元测试期间]正确地处理记录?]



UPDATE:好的,所以我尝试了使用阅读器内部的服务进行更结构化的方法:

@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
  }

所以我做错了什么?

我正在尝试为Spring Batch应用程序编写测试,尤其是以下读者在从实现简单RowMapper的数据库中获取记录时与以下读者的交互:@ ...] >> [[

关于测试数据库交互,我不会嘲笑读者。相反,我将使用嵌入式数据库并用测试数据填充它。这可以通过将以下bean添加到您的测试上下文中来实现:

@Bean public DataSource dataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .addScript("/org/springframework/batch/core/schema-drop-h2.sql") .addScript("/org/springframework/batch/core/schema-h2.sql") .addScript("/schema.sql") .addScript("/test-data.sql") .build(); }

此示例使用H2,但是您可以使用derby或HSLQ或SQLite或任何其他可嵌入的数据库。
java unit-testing groovy spring-batch spock
1个回答
1
投票
关于测试数据库交互,我不会嘲笑读者。相反,我将使用嵌入式数据库并用测试数据填充它。这可以通过将以下bean添加到您的测试上下文中来实现:

@Bean public DataSource dataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .addScript("/org/springframework/batch/core/schema-drop-h2.sql") .addScript("/org/springframework/batch/core/schema-h2.sql") .addScript("/schema.sql") .addScript("/test-data.sql") .build(); }

此示例使用H2,但是您可以使用derby或HSLQ或SQLite或任何其他可嵌入的数据库。
© www.soinside.com 2019 - 2024. All rights reserved.