rss

Unit test of a spring scheduler configuration using Mockito.spy

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

Mots clés du blog

acceptancetest androï Android androïd Android7 api appender appengine application applications archive array assistantematernelle astuce auth0 authentication authority automation Axis bash bearer blog bower build bundle c calendrier camille combal cdi certificate cf client cloudfoundry collaboratif command commandes connexion console css démasquées démasquer développement dll dump easter eggs écologie écrit employeur EMUI EMUI5.0 enfant évènement export-package ExtJS fiche find firefox gadget gelf gem git gmail gooelappengine google gparted gps graylog grenoble Grid gui harddrive heroku hover howto HTML http https IE ihm immobilier imprimante innovation insolite instance integration Java JavaScript jenkins jeu jobs json json-schema-validator key keystore labs linux livre log log4j logger logs lombok masquées masquer maven maven-gae-plugin Mémoire microsoft mobile mockito mondialisation monitor MUSE musique en ligne myopera nodejs npm NT NTEventLogger onglet openstack osgi paas package parameters parent php politique prosyst prototype proxies proxy quartz radio rappel recherche regex repository resize RIA rock route ruby rubygems s8500 samsung scheduler scm sel selenium Serializer server shared shell slf4j smartphone so société song spy ssh ssl struct swagger swig tâches téléphone téléréalité test thunderbird timeout token Tomcat tooltip tooltips truststore ubuntu unit test validator virgin virtualbox wave waze web WebApp wiki wikimedia wikipédia wikipen windows yahoo youtube yum