Почему это
Если вы хотите использовать StepScopeTestExecutionListener
, тестируемый компонент должен иметь ступенчатую область действия (см. Javadoc ). Это не тот случай в вашем примере. Но это не настоящая проблема. Реальная проблема заключается в том, что метод, помеченный @BeforeStep
, будет вызываться перед выполнением шага, на котором зарегистрирован ваш процессор. В вашем тестовом примере шаг не выполняется, поэтому метод никогда не вызывается.
как этого добиться?
Поскольку это модульное тестирование, вы можете предполагать, что выполнение шага будет передано вашему процессору элементов Spring Batch перед выполнением шага и макетировать / заглушить его в модульном тесте. Вот как я бы тестировал компонент:
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.core.StepExecution;
import static org.junit.Assert.assertNotNull;
public class MegaProcessorTest {
private MegaProcessor sut;
@Before
public void setUp() {
StepExecution execution = MetaDataInstanceFactory.createStepExecution();
execution.getExecutionContext().put("data", "yeah");
sut = new MegaProcessor();
sut.getExecutionContext(execution); // I would rename getExecutionContext to setExecutionContext
}
@Test
public void MegaProcessor() throws Exception {
assertNotNull(sut.process("pew pew"));
}
}
StepScopeTestExecutionListener
удобен, когда у вас есть компоненты с шаговой областью, которые используют позднюю привязку для получения значений из контекста выполнения шага. Например:
@Bean
@StepScope
public ItemReader<String> itemReader(@Value("#{stepExecutionContext['items']}") String[] items) {
return new ListItemReader<>(Arrays.asList(items));
}
Юнит-тест этого читателя будет выглядеть примерно так:
import java.util.Arrays;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
@ContextConfiguration(classes = StepScopeExecutionListenerSampleTest.MyApplicationContext.class)
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, StepScopeTestExecutionListener.class })
@RunWith(SpringRunner.class)
public class StepScopeExecutionListenerSampleTest {
@Autowired
private ItemReader<String> sut;
public StepExecution getStepExecution() {
StepExecution execution = MetaDataInstanceFactory.createStepExecution();
execution.getExecutionContext().put("items", new String[] {"foo", "bar"});
return execution;
}
@Test
public void testItemReader() throws Exception {
Assert.assertEquals("foo", sut.read());
Assert.assertEquals("bar", sut.read());
Assert.assertNull(sut.read());
}
@Configuration
static class MyApplicationContext {
@Bean
@StepScope
public ItemReader<String> itemReader(@Value("#{stepExecutionContext['items']}") String[] items) {
return new ListItemReader<>(Arrays.asList(items));
}
/*
* Either declare the step scope like the following or annotate the class
* with `@EnableBatchProcessing` and the step scope will be added automatically
*/
@Bean
public static org.springframework.batch.core.scope.StepScope stepScope() {
org.springframework.batch.core.scope.StepScope stepScope = new org.springframework.batch.core.scope.StepScope();
stepScope.setAutoProxy(false);
return stepScope;
}
}
}
Надеюсь, это поможет.