rss
twitter
    Suivez-moi sur Twitter ! :)

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>  

Selenium Acceptance/Integration Tests for a Google App Engine application using maven-gae-plugin

Hi,
 this is just a little tip on how to setup selenium acceptance tests for a Google App Engine java application when using maven-gae-plugin.
  • First, be sure you are using an earlier version (> 0.9.6 release ; eg. the latest snapshot version) of maven-gae-plugin.
    Here is an extract of a pom for the plugin repository and selenium deps right here :

  <properties>  
     <selenium.version>2.15.0</selenium.version>  
     <maven-gae-plugin.version>0.9.7-SNAPSHOT</maven-gae-plugin.version>  
   </properties>  


 <pluginrepositories>  
     <pluginrepository>  
       <id>sonatype.snapshots</id>  
       <url>https://oss.sonatype.org/content/repositories/snapshots/</url>  
       <releases><enabled>true</enabled></releases>  
       <snapshots><enabled>true</enabled></snapshots>  
     </pluginrepository>  
 </pluginrepositories>  
     <!-- acceptance tests -->  
     <dependency>  
       <groupid>org.seleniumhq.selenium</groupid>  
       <artifactid>selenium-java</artifactid>  
       <version>${selenium.version}</version>  
       <scope>test</scope>  
     </dependency>  

  • Then, map the gae-start and gae-stop executions to the pre/post integration phases. This is an example of the plugin configuration :
      <plugin>  
         <groupid>net.kindleit</groupid>  
         <artifactid>maven-gae-plugin</artifactid>  
         <version>${maven-gae-plugin.version}</version>  
         <configuration>  
           <unpackversion>${gae.version}</unpackversion>  
           <serverid>appengine.google.com</serverid>  
           <appdir>${webappDirectory}</appdir>  
         </configuration>  
         <executions>  
           <execution>  
             <id>unpack</id>  
             <phase>validate</phase>  
             <goals>  
               <goal>unpack</goal>  
             </goals>  
           </execution>  
           <execution>  
             <id>deploy</id>  
             <goals>  
               <goal>deploy</goal>  
             </goals>  
           </execution>  
           <execution>  
             <id>gae-start</id>  
             <phase>pre-integration-test</phase>  
             <goals>  
               <goal>start</goal>  
             </goals>  
             <configuration>  
               <appdir>${webappDirectory}</appdir>  
               <port>9000</port>  
               <address>0.0.0.0</address>
               <sdkdir>${gae.home}</sdkdir>  
               <wait>false</wait>  
               <disableupdatecheck>true</disableupdatecheck>  
             </configuration>  
           </execution>  
           <execution>  
             <id>gae-stop</id>  
             <phase>post-integration-test</phase>  
             <goals>  
               <goal>stop</goal>  
             </goals>  
           </execution>  
         </executions>  
         <dependencies>  
           <dependency>  
             <groupid>net.kindleit</groupid>  
             <artifactid>gae-runtime</artifactid>  
             <version>${gae-runtime.version}</version>  
             <type>pom</type>  
           </dependency>  
         </dependencies>  

  • The next and last step is to write your acceptance test. Here is just a simple example :
 package net.mademocratie.gae.acceptancetest;  
 import org.junit.After;  
 import org.junit.Before;  
 import org.junit.Test;  
 import org.openqa.selenium.WebDriver;  
 import org.openqa.selenium.firefox.FirefoxDriver;  
 import static com.thoughtworks.selenium.SeleneseTestBase.assertEquals;  
 public class HomePageIT {  
   private WebDriver driver;  
   @Before  
   public void setUp() {  
     driver = new FirefoxDriver();  
   }  
   @Test  
   public void home_page_should_be_displayed() {  
     this.driver.get("http://localhost:9000");  
     assertEquals("Ma Democratie", this.driver.getTitle());  
   }  
   @After  
   public void tearDown() {  
     driver.quit();  
   }  
 }  

You should find a full running sample on the github repository of ma-dem-ae.
NB: (possible) related issue #5
PS: thanks to codeformatter for this post ;)
PS(bis): oO i just heard that CasperJS or cucumber.js could do the job too...

Un tooltip rapide stp..

Holla,

 voici un petit bout de code Html et Css permettant d'afficher un Tooltip

sources : post d'inspiration initiale + les lumières de Ludo & surtout Thomas ^^ ...

code html :

<div class="showtooltipA">Hover over me!
    <div class="tooltipA">this is my <href="http://google.fr">wunderfull</atip displayed on hover only :)</div>
</div>


code css :

.showtooltipA {
  positionrelative;
}

.showtooltipA .tooltipA {
    displaynone;
    positionabsolute;
    top:20px;
    left40px;
    border1px solid grey;
    background-colorlightyellow;
    padding:10px;
    font-size1em;

}

.showtooltipA:hover .tooltipA,
.showtooltipA:focus .tooltipA {
    displayblock;
}

 testez en live ici : http://jsfiddle.net/Vqmaw/2915/
  version plus avancée : http://jsfiddle.net/Vqmaw/2920/

avantages :
  • rapide à implémenter
  • pas de dépendances requises
  • pas de modification de la position des éléments encadrant le tooltip
inconvénients :
  • très (trop?) simpliste 
Autres exemples :