Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Junits for classes extending QuartzJobBean

Tags:

junit

I have a Java class that extends QuartzJobBean and has been scheduled at a specific time through out the day.

   public class ServiceJob extends QuartzJobBean {

        @Override
          protected void executeInternal(JobExecutionContext context) {
}

Can someone please help me understand how to create a Junit test case for this. How do I invoke the executeInternal() method in the test case.

Thanks for any help on this.

like image 665
adarshdatt Avatar asked Dec 18 '14 17:12

adarshdatt


1 Answers

I create a solution for my working project, i agree to adarshdatt to solve it via importing config file that defined the bean. You can find a good tutorial about it at this blog post,

For future use I want to show how i solve it with Mocking, just use Mockito @Mock annotation with this way :

SessionConfirmationJob.java

public class SessionConfirmationJob extends QuartzJobBean {
    @Autowired
    private SessionService sessionService;
    @Autowired
    private TransactionService transactionService;
    @Autowired
    private SystemLogger systemLogger;
    public static final String TOKEN = "token";
    private SpringInjectQuartzJobBean springInjectQuartzJobBean;

    public SessionService getSessionService() {
        return sessionService;
    }

    public void setSessionService(SessionService sessionService) {
        this.sessionService = sessionService;
    }

    public TransactionService getTransactionService() {
        return transactionService;
    }

    public void setTransactionService(TransactionService transactionService) {
        this.transactionService = transactionService;
    }

    public void setSpringInjectQuartzJobBean(SpringInjectQuartzJobBean springInjectQuartzJobBean) {
        this.springInjectQuartzJobBean = springInjectQuartzJobBean;
    }

    public SystemLogger getSystemLogger() {
        return systemLogger;
    }

    public void setSystemLogger(SystemLogger systemLogger) {
        this.systemLogger = systemLogger;
    }

    @Override
    protected void executeInternal(JobExecutionContext paramJobExecutionContext) throws JobExecutionException {
        springInjectQuartzJobBean = new SpringInjectQuartzJobBean();
        springInjectQuartzJobBean.injectQuartzJobToSpringApplicationContext(this);
        String token = paramJobExecutionContext.getMergedJobDataMap().getString(TOKEN);
        Session session = sessionService.getByToken(token);
        if (session != null) {
            if (session.getPaymentConfirmation() == null || session.getPaymentConfirmation() != true) {
                Transaction transactionToBeRolledBack = transactionService.getRollBackTransactionOfPayment(session);
                if (transactionToBeRolledBack != null) {
                    try {
                        transactionService.rollBackTransaction(transactionToBeRolledBack);
                    } catch (IOException e) {
                        systemLogger.logException("Exception while rolling back transaction", e);
                    }
                    session = sessionService.getByToken(token);
                    session.setStatus(SessionStatus.FI);
                    session.setPaymentConfirmation(false);
                    sessionService.saveOrUpdate(session);
                }
            }
        }
    }
}

This is the method i should write test and this is the testing class.

SessionConfirmationJobTest.java

@RunWith(MockitoJUnitRunner.class)
public class SessionConfirmationJobTest {
    @Mock
    private SessionService sessionService;
    @Mock
    private TransactionService transactionService;
    @Mock
    private JobExecutionContext ctx;
    @Mock
    private SpringInjectQuartzJobBean springInjectQuartzJobBean;
    private JobDataMap mergedJobDataMap = new JobDataMap();
    @Mock
    private Scheduler scheduler;
    private SessionConfirmationJob sessionConfirmationJob;
    private String token = "payment token";

    @Before
    public void setUp() throws SchedulerException {
        mergedJobDataMap.put(SessionConfirmationJob.TOKEN, token);
        when(ctx.getMergedJobDataMap()).thenReturn(mergedJobDataMap);
        when(ctx.getScheduler()).thenReturn(scheduler);
        when(scheduler.getContext()).thenReturn(null);
        sessionConfirmationJob = new SessionConfirmationJob();
        sessionConfirmationJob.setSessionService(sessionService);
        sessionConfirmationJob.setTransactionService(transactionService);
        sessionConfirmationJob.setSpringInjectQuartzJobBean(springInjectQuartzJobBean);
    }

    /**
     * Test payment confirmation when we have false payment confirmation
     * 
     * @throws JobExecutionException
     */
    @Test
    public void testPaymentRollBackForFalseConfirmation() throws IOException, JobExecutionException {
        Session session = new Session();
        session.setStatus(SessionStatus.AC);
        session.setPaymentConfirmation(false);
        Transaction transaction = new Transaction();
        transaction.setSession(session);
        transaction.setType(TransactionType.SALE);
        transaction.setStatus(TransactionStatus.AP);
        when(sessionService.getByToken(token)).thenReturn(session);
        when(transactionService.getRollBackTransactionOfPayment(session)).thenReturn(transaction);
        when(transactionService.rollBackTransaction(transaction)).thenReturn(true);
        sessionConfirmationJob.execute(ctx);
        Assert.assertEquals(SessionStatus.FI, session.getStatus());
        Assert.assertFalse(session.getPaymentConfirmation());
        verify(sessionService).saveOrUpdate(session);
    }
}

Before mock the Schedular object i get NullPointerException at pvs.addPropertyValues(context.getScheduler().getContext()); after i mock schedular it is solved and my test is passed. Below is the

org.springframework.scheduling.quartz.QuartzJobBean#execute(JobExecutionContext context) method. Actually executeInternal is protected so we must call execute method first then execute method is call executeInternal which is override at your implemented Job class(my demo it is SessionConfirmationJob).

QuartzJobBean.java

public abstract class QuartzJobBean implements Job {

    /**
     * This implementation applies the passed-in job data map as bean property
     * values, and delegates to {@code executeInternal} afterwards.
     * @see #executeInternal
     */
    @Override
    public final void execute(JobExecutionContext context) throws JobExecutionException {
        try {
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
            MutablePropertyValues pvs = new MutablePropertyValues();
            pvs.addPropertyValues(context.getScheduler().getContext());
            pvs.addPropertyValues(context.getMergedJobDataMap());
            bw.setPropertyValues(pvs, true);
        }
        catch (SchedulerException ex) {
            throw new JobExecutionException(ex);
        }
        executeInternal(context);
    }

/**
 * Execute the actual job. The job data map will already have been
 * applied as bean property values by execute. The contract is
 * exactly the same as for the standard Quartz execute method.
 * @see #execute
 */
protected abstract void executeInternal(JobExecutionContext context) throws JobExecutionException;

}

If you have question don't hesitate to ask me via comments.

like image 164
erhun Avatar answered Dec 12 '22 16:12

erhun