在单元测试执行期间未调用@BeforeStep方法 [英] @BeforeStep method is not called during unit test execution

查看:59
本文介绍了在单元测试执行期间未调用@BeforeStep方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 ItemProcessor ,它具有一个 @BeforeStep 方法来访问 ExecutionContext :

I have an ItemProcessor which has a @BeforeStep method to access the ExecutionContext:

public class MegaProcessor implements ItemProcessor<String, String> {

    private ExecutionContext context;

    @BeforeStep
    void getExecutionContext(final StepExecution stepExecution) {
        this.context = stepExecution.getExecutionContext();
    }

    @Override
    public String process(final String string) throws Exception {
     // ...
    }
}

此类的单元测试:

@ContextConfiguration(classes = MegaProcessor.class)
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, StepScopeTestExecutionListener.class })
@RunWith(SpringRunner.class)
public class MegaProcessorTest {

    @Autowired
    private MegaProcessor sut;

    public StepExecution getStepExecution() {
        StepExecution execution = MetaDataInstanceFactory.createStepExecution();
        execution.getExecutionContext().put("data", "yeah");
        return execution;
    }

    @Test
    public void MegaProcessor() throws Exception {
        assertNotNull(sut.process("pew pew"));
    }
}

当我调试测试运行时, context null ,并且永远不会调用 @BeforeStep 方法.为什么会这样以及如何实现呢?

When I debug the test run, context is null and the @BeforeStep method is never called. Why is that and how to achieve that?

推荐答案

那是为什么

如果要使用 StepScopeTestExecutionListener ,则应对受测组件进行步进作用域检查(请参阅

If you want to use the StepScopeTestExecutionListener, the tested component should be step-scoped (See Javadoc). It's not the case in your example. But this is not the real issue. The real issue is that the method annotated with @BeforeStep will be called before the step in which your processor is registered is executed. In your test case, there is no step running so the method is never called.

如何实现?

由于它是一个单元测试,因此您可以假设在运行步骤并将其模拟/存入单元测试之前,Spring Batch将把步骤执行传递给项目处理器.这就是我对组件进行单元测试的方式:

Since it is a unit test, you can assume the step execution will be passed to your item processor by Spring Batch before running the step and mock/stub it in your unit test. This is how I would unit test the component:

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 非常方便.例如:

The StepScopeTestExecutionListener is handy when you have step-scoped components that use late-binding to get values from the step execution context. For example:

@Bean
@StepScope
public ItemReader<String> itemReader(@Value("#{stepExecutionContext['items']}") String[] items) {
        return new ListItemReader<>(Arrays.asList(items));
}

该阅读器的单元测试将类似于:

A unit test of this reader would be something like:

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

}

希望这会有所帮助.

这篇关于在单元测试执行期间未调用@BeforeStep方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆