编程语言
首页 > 编程语言> > java-Spring Batch Job的集成测试失败

java-Spring Batch Job的集成测试失败

作者:互联网

好的,我知道从标题看这听起来很简单,但确实让我很困惑为什么会这样.

因此,我正在使用Spring Batch生成要使用Amazon的Simple Email Service发送的电子邮件.在我的CustomItemProcessor内部,我使用@Autowired正常连接我的AmazonEmailService服务. AmazonEmailService类实现了我的EmailSender接口.

AmazonEmailService具有@Autowired AmazonSimpleEmailServiceClient,它用于实际调用Amazon Simple Email Service来执行操作.

我的AmazonSimpleEmailServiceClient bean在我的root-servlet.xml中定义:

<bean id="amazonSimpleEmailServiceClient"
    class="com.amazonaws.services.simpleemail.AmazonSimpleEmailServiceClient">
    <constructor-arg ref="basicAWSCredentials" />
</bean>

<bean id="basicAWSCredentials" class="com.amazonaws.auth.BasicAWSCredentials">
    <constructor-arg index="0" value="${aws.accessKey}"/>
    <constructor-arg index="1" value="${aws.secretKey}" />
</bean>

所有这些都很好.

我的问题是,当我运行Spring Batch Job集成测试时.他们在尝试发送电子邮件时挂起.我的日志记录显示执行只是在对AmazonSimpleEmailServiceClient.send(emailRequest)的调用处停止,并且没有继续.

让我感到困惑的是,如果在为Spring Batch Jobs进行集成测试之前运行AmazonEmailService的单元测试,那么一切都将成功完成.我想知道为什么会这样.值得一提的是,实际发送电子邮件的批处理作业具有在单个线程上运行的TaskExecutor.

应对Spring Batch作业进行集成测试,以验证该作业是否成功为其收到的每个输入生成了一封电子邮件,并且可以使用Amazon SES发送这些电子邮件.它还测试它是否正确地将对象读取和写入设置的队列,但这与我的问题无关. AmazonEmailService的单元测试仅向Amazon电子邮件模拟器发送3封电子邮件.

我将在下面发布一个简化的类图,以便您可以看到事物如何结合在一起.

> EmailService接口是我自己的接口.
> AmazonEmailService是我自己的服务.该服务实际上使用AmazonSimpleEmailServiceClient执行电子邮件的发送,该对象是Amazon提供给我的对象.
> CustomItemProcessor是我自己的实现ItemProcessor接口的对象.这就是Spring Batch用来对批处理作业中的项目进行实际处理的东西.电子邮件应由此类生成和发送.
> AmazonEmailServiceTest只是测试功能的单元测试
以实际发送电子邮件.

在考虑为什么我遇到这个愚蠢的问题时,您可能会想到的事情:

>我已经正确配置了单元/集成测试以在Spring应用程序上下文中运行.
> AmazonEmailServiceTest独自成功运行.
>如果我恢复为使用简单的JavaMail电子邮件发件人,则Spring Batch集成测试将成功运行.
>使用XML config为我的所有其他类正确配置和定义了我的Spring Batch作业,应用程序上下文和bean.
>我的Amazon凭证有效并且可以正常工作.
>班级正确地自动接线.
>尝试单独或与AmazonEmailServiceTest一起运行Spring Batch测试的任何阶段都不会引发异常
>一起运行测试时,AmazonEmailService的相同实例将自动连接到两个测试中(即,两个测试使用相同的内存地址,等等)
>我无法检查实际单元测试中使用的凭据.
>我已经在XML配置中正确配置了PropertyPlaceholderConfigurer.
>在我手动停止单元测试之前,对amazonSimpleEmailServiceClient.send(emailRequest)的调用将挂起.
>可以在应用程序上下文中发现相关的Bean,以进行自动装配.

如果您需要更多信息,例如类或配置,请随时询问.我实际上是坐在电脑前等待回复.

AmazonEmailService:

@Service
public class AmazonEmailService implements EmailService {

    @Autowired
    private AmazonSimpleEmailServiceClient amazonSimpleEmailServiceClient;

    @Override
    public String sendEmail(Email email){
        //build request using Builder pattern//
        return amazonSimpleEmailServiceClient.sendEmail(emailRequest);
    }
}

CustomItemProcessor:

public class CustomProcessQueueItemProcessor implements
    ItemProcessor<Foo, Bar> {

    @Autowired
    private EmailService amazonEmailService;

    @Override
    public Bar process(Foo foo) throws Exception {
        //generate email from Foo object//
        String result = amazonEmailService.sendEmail(email);
        //create Bar object from result//
        return bar;
    }
}

AmazonEmailServiceTest:

public class AmazonEmailServiceTest extends SpringTest{

@Autowired
private EmailService amazonEmailService;

@Test
public void testSendEmailSuccess() {
    Email successEmail = MockObjectFactory.setTestSuccessEmail();
    String emailResultId = amazonEmailService.sendEmail(successEmail);
    assertNotNull("The returned emailResultId was null", emailResultId);
}
}

我在SpringTest类中配置单元测试以在Spring应用程序上下文中运行.顾名思义,我的MockObjectFactory是一个包含用于生成测试对象的静态方法的类.

批处理Servlet:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:batch="http://www.springframework.org/schema/batch"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.2.xsd">

    <import resource="jobs/fill-queue-job.xml" />
    <import resource="jobs/process-queue-job.xml" />

    <batch:job-repository id="jobRepository"
        data-source="dataSource" transaction-manager="transactionManager" />

    <bean id="jobLauncher"
        class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
        <property name="jobRepository" ref="jobRepository" />
        <property name="taskExecutor" ref="defaultTaskExecutor"></property>
    </bean>

    <bean id="jobRegistry"
        class="org.springframework.batch.core.configuration.support.MapJobRegistry" />

    <bean id="jobRegistryBeanPostProcessor"
        class="org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor">
        <property name="jobRegistry" ref="jobRegistry" />
    </bean>

    <bean id="jobLoader"
        class="org.springframework.batch.core.configuration.support.DefaultJobLoader">
        <property name="jobRegistry" ref="jobRegistry" />
    </bean>

    <bean id="jobExplorer"
        class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="jobOperator"
        class="org.springframework.batch.core.launch.support.SimpleJobOperator">
        <property name="jobLauncher" ref="jobLauncher" />
        <property name="jobRepository" ref="jobRepository" />
        <property name="jobRegistry" ref="jobRegistry" />
        <property name="jobExplorer" ref="jobExplorer" />
    </bean>

    <bean id="domainObjectIdQueue" class="java.util.concurrent.ConcurrentLinkedQueue" />

    <bean id="mainQueue" class="java.util.concurrent.ConcurrentLinkedQueue" />

    <bean id="notificationQueue" class="java.util.concurrent.ConcurrentLinkedQueue" />

    <bean id="fillQueueItemReader"
        class="au.com.mail.batch.itemreaders.CustomServiceItemReader"
        scope="step">
        <constructor-arg ref="emailTaskServiceImpl" />
    </bean>

    <bean id="fillQueueItemProcessor"
        class="au.com.mail.batch.itemprocessors.CustomFillQueueItemProcessor"
        scope="step" />

    <bean id="fillQueueCompositeItemWriter"
        class="org.springframework.batch.item.support.CompositeItemWriter">
        <property name="delegates">
            <list>
                <bean id="fillQueueItemWriter"
                    class="au.com.mail.batch.itemwriters.CustomQueueItemWriter"
                    scope="step" />
                <bean id="emailTaskItemWriter"
                    class="au.com.mail.batch.itemwriters.CustomServiceItemWriter"
                    scope="step">
                    <constructor-arg ref="emailTaskServiceImpl" />
                </bean>
            </list>
        </property>
    </bean>

    <bean id="processQueueItemReader"
        class="au.com.mail.batch.itemreaders.CustomQueueItemReader"
        scope="step">
        <constructor-arg>
            <value type="java.lang.Class">au.com.mail.domainobject.messagewrappers.MainQueueMessageWrapper
            </value>
        </constructor-arg>
    </bean>

    <bean id="processQueueItemProcessor"
        class="au.com.mail.batch.itemprocessors.CustomProcessQueueItemProcessor"
        scope="step" />

    <bean id="processQueueItemWriter"
        class="au.com.mail.batch.itemwriters.CustomQueueItemWriter"
        scope="step" />

    <bean id="defaultTaskExecutor"
        class="org.springframework.scheduling.quartz.SimpleThreadPoolTaskExecutor">
        <property name="threadCount" value="5" />
    </bean>

    <bean id="processQueueTaskExecutor"
        class="org.springframework.scheduling.quartz.SimpleThreadPoolTaskExecutor">
        <property name="threadCount" value="1" />
    </bean>


    <bean id="customStepExecutionListener" class="au.com.mail.batch.CustomStepExecutionListener"
        scope="step" />

    <bean id="jobLauncherTestUtils" class="org.springframework.batch.test.JobLauncherTestUtils">
        <property name="job" ref="fillQueue" />
        <property name="jobRepository" ref="jobRepository" />
        <property name="jobLauncher" ref="jobLauncher" />
    </bean>
</beans>

流程队列作业定义:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/batch"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.2.xsd">

    <beans:bean id="repeatQueueOpenTasklet"
        class="au.com.mail.batch.CustomQueueRetryTaskletImpl" scope="step" />

    <job id="processQueue" job-repository="jobRepository">
        <step id="getQueue">
            <tasklet ref="repeatQueueOpenTasklet" task-executor="processQueueTaskExecutor">
            </tasklet>
            <end on="FAILED" exit-code="NOOP" />
            <next on="*" to="sendEmail" />
        </step>
        <step id="sendEmail">
            <tasklet task-executor="processQueueTaskExecutor">
                <chunk reader="processQueueItemReader" processor="processQueueItemProcessor"
                    writer="processQueueItemWriter" commit-interval="5" />
            </tasklet>
            <listeners>
                <listener ref="customStepExecutionListener"></listener>
            </listeners>
        </step>
    </job>
</beans:beans>

大更新:
我从流程队列Tasklet上删除了processQueueTaskExecutor,并从jobLauncher中删除了defaultTaskExecutor,Amazon服务调用成功.现在我只需要知道为什么会这样.

解决方法:

从您的帖子中还不清楚您的“单元”测试实际上是在尝试测试.可以肯定地说,亚马逊的电子邮件服务已经过了良好的测试,并且不需要在单元测试中进行实际测试.

相反,您可以为您的单元测试创​​建一个新的测试Spring上下文,以提供EmailService的模拟,然后在您的单元测试中验证在您期望的时候实际上正在调用emailService.sendEmail(…)方法,与您期望的内容.这样,您的测试就无需与任何实际的电子邮件服务进行交互.

标签:amazon-ses,spring-batch,integration-testing,spring,java
来源: https://codeday.me/bug/20191121/2054932.html