Hello,
here is a little sample on how to write scheduled monitoring unit test using spring and mockito spy factory method.
In the legacy code there is a job that is defined to purge the database each 8 hour using a spring defined quarrtz job:
scheduled-service-context.xml
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemalocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<bean class="com.foo.ScheduledDatabasePurgeMonitor"
id="scheduledDatabasePurgeMonitor">
</bean></beans>
scheduled-trigger-context.xml
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemalocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<bean class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean" id="scheduledDatabasePurgeJob">
<property name="targetObject" ref="scheduledDatabasePurgeMonitor">
<property name="targetMethod" value="doIt">
<property name="concurrent" value="false">
</property></property></property></bean>
<bean class="org.springframework.scheduling.quartz.SimpleTriggerBean" id="databasePurgeTrigger">
<!-- see the example of method invoking job above -->
<property name="jobDetail" ref="scheduledDatabasePurgeJob">
<!-- first start after 1 milliseconds -->
<property name="startDelay" value="1">
<!-- repeat every (schedule.databasePurge.repeatIntervalMs) milliseconds / default 8 hours -->
<property name="repeatInterval" value="${schedule.databasePurge.repeatIntervalMs:28800000}">
</property></property></property></bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="databasePurgeTrigger">
</ref></list>
</property>
</bean>
<!-- official howto :
http://static.springsource.org/spring/docs/3.0.5.RELEASE/reference/scheduling.html#scheduling-quartz
-->
</beans>
here is the sample purgemonitor class:
/**
* ScheduledDatabasePurgeMonitor
*/
public class ScheduledDatabasePurgeMonitor {
private final static Logger logger = LoggerFactory.getLogger(ScheduledDatabasePurgeMonitor.class.getName());
public void doIt() {
logger.debug("database purge right now");
purgeDatabase();
}
void purgeDatabase() {
logger.debug("* purge database *");
}
}
we would like to ensure in an unit test that the spring configuration enable the purge scheduling each N ms :
- we would like a little N to avoid an 8 hour unit test
- we would like to mock the purge service
So we need a sping spy'ed bean and here is a way to do this :
Unit test class :
package com.foo; import org.junit.Assert; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; /** * ScheduledDatabasePurgeMonitorTest IT Test of the database purge monitoring */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration public class ScheduledDatabasePurgeMonitorTest { private final static Logger logger = LoggerFactory.getLogger(ScheduledDatabasePurgeMonitorTest.class.getName()); @Autowired ScheduledDatabasePurgeMonitor scheduledDatabasePurgeMonitor; @Autowired private Integer purgeRepeatIntervalMs; @Before public void setup() { // avoid the database purge here doNothing().when(scheduledDatabasePurgeMonitor).purgeDatabase(); } /** * GIVEN ScheduledDatabasePurgeMonitor implementation WHEN scheduler * trigger THEN purge service is called * */ @Test public void database_purge_monitor_should_be_periodically_invoked() { // THEN logger.info("verify first call of purgeDatabase"); int callNumber = 1; verify(scheduledDatabasePurgeMonitor, times(callNumber)).purgeDatabase(); for (int i=0; i<3 ; i++) { waitForNextScheduledUpdate();callNumber++; logger.info("verify next call ({}) of purgeDatabase", callNumber); verify(scheduledDatabasePurgeMonitor, times(callNumber)).purgeDatabase(); } } private void waitForNextScheduledUpdate() { try { long waitIntMs = getPurgeRepeatIntervalMs() + 100; logger.debug("wait for {} seconds", (waitIntMs / 1000)); Thread.sleep(waitIntMs); } catch (InterruptedException e) { Assert.fail("InterruptedException oO"); } } public ScheduledDatabasePurgeMonitor getScheduledDatabasePurgeMonitor() { return scheduledDatabasePurgeMonitor; } public void setScheduledDatabasePurgeMonitor(ScheduledDatabasePurgeMonitor scheduledDatabasePurgeMonitor) { this.scheduledDatabasePurgeMonitor = scheduledDatabasePurgeMonitor; } public Integer getPurgeRepeatIntervalMs() { return purgeRepeatIntervalMs; } public void setPurgeRepeatIntervalMs(Integer purgeRepeatIntervalMs) { this.purgeRepeatIntervalMs = purgeRepeatIntervalMs; } }
Unit test spring context :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="classpath:/META-INF/spring/jasypt-context.xml"/>
<bean class="org.jasypt.spring31.properties.EncryptablePropertySourcesPlaceholderConfigurer" depends-on="jasyptPrerequisites">
<constructor-arg ref="configurationEncryptor"/>
<property name="locations">
<list>
<value>classpath:credentials.properties</value>
<value>classpath:/com/foo/scheduled-database-purge.properties</value>
</list>
</property>
</bean>
<bean id="toSpyScheduledDatabasePurgeMonitor"
class="com.foo.ScheduledDatabasePurgeMonitor"/>
<bean id="scheduledDatabasePurgeMonitor"
class="org.mockito.Mockito" factory-method="spy">
<constructor-arg ref="toSpyScheduledDatabasePurgeMonitor" />
</bean>
<import resource="classpath:META-INF/spring/services-scheduled-trigger-context.xml"/>
<bean id="purgeRepeatIntervalMs" class="java.lang.Integer">
<constructor-arg value="${schedule.databasePurge.repeatIntervalMs}"/>
</bean>
</beans>
unit test properties file :
# test purpose : ask iaas quota each 2 seconds schedule.databasePurge.repeatIntervalMs=2000
you would notice that Mockito.spy(object)
static method is used into the spring unit test context :
<bean id="scheduledDatabasePurgeMonitor"
class="org.mockito.Mockito" factory-method="spy">
<constructor-arg ref="toSpyScheduledDatabasePurgeMonitor" />
</bean>
Aucun commentaire:
Enregistrer un commentaire