Thursday, August 13, 2015

MXJUnit: Testing Crons

MXJUnit provides the ability to unit test crons.  This means that, within a JUnit test case, it is possible to execute a cron and test what it does.  MXJunit goes one step further and allows you to execute the cron with a subclass of what's defined in Maximo.  This allows a change to change the behaviour of the cron for the test.  Normally, I use this to provide a different SQL where clause so the test operates on a smaller and/or known subset of the data.

Most MXJUnit tests will extend from MaximoTestHarness.  A test that has to execute a cron task must extend from CronTaskTestHarness.   This provides methods to execute a cron, but also performs some additional work behind the scenes that isn't normally required.

This example executes the KPIHISTORY cron which goes through the KPIHISTORY table and deletes records more than a year old.  These examples should be executable in any Maximo environment.


 public class CronTaskDemo1Test extends CronTaskTestHarness {  
      /**  
       * Test that KPIHISTORY cron will delete old KPIHISOTRY records.  
       *   
       * @throws RemoteException if an RMI problem occurs.  
       * @throws MXException if a Maximo problem occurs.  
       */  
      @Test  
      public void testKPIHistory() throws RemoteException, MXException {  
           // create a new KPI History record for testing.  
           MboRemote kpiHistory = createKpiHistory();  

           // load it and verify that it exists and is properly populated  
           kpiHistory = refresh(kpiHistory);  
           assertNotNull(kpiHistory);  
           assertEquals(pastDate(), kpiHistory.getDate("RECORDEDON"));  

           // run the cron  
           runCron("KPIHISTORY", "KPIHISTORY1YEAR");  

           // attempt to reload the KPIHISTORY and note that it is gone.   
           kpiHistory = refresh(kpiHistory);  
           assertNull(kpiHistory);  
      }

     // ... snip ...  
 }  

The full source is available in CronTaskDemo1Test.java

The runCron() method executes the cron.  It must refer to an existing definition in the Maximo cron task tables (CRONTASKDEF, CRONTASKINSTANCE).  It will execute the cron with the parameters defined for the named cron task instance.  The cron does not need to be active in Maximo for the cron to execute it.

That's all there is to running a cron in an MXJUnit test.  After the test, make sure to test that the cron performed the intended work.


 public class CronTaskDemo2Test extends CronTaskTestHarness {  
   
      public static class DemoCron extends KPIHistoryCleanupCronTask {  
           @Override  
           public void cronAction() {  
                throw new RuntimeException("Stopped!");  
           }            
      }  
        
      /**  
       * Test that KPIHISTORY cron will delete old KPIHISOTRY records.  
       *   
       * @throws RemoteException if an RMI problem occurs.  
       * @throws MXException if a Maximo problem occurs.  
       */  
      @Test  
      public void testKPIHistory() throws RemoteException, MXException {  
           try {  
                // run the cron  
                runCron(DemoCron.class, "KPIHISTORY", "KPIHISTORY1YEAR");  
                fail("Exception expected");  
           } catch (RuntimeException e) {  
                assertEquals("Stopped!", e.getMessage());  
           }       
      }            
 }  

The full source is available in CronTaskDemo2Test.java

Many crons I've written involve data transfers or data updates.  By writing the cron with a method to retrieve or generate an SQL where clause to identify the data on which to operate, it is possible to use MXJUnit to substitute a different where clause for testing.

This example replaces the cronAction() of the KPIHISTORY cron to throw an error.  A new class, DemoCron is created to extend from KPIHistoryCleanupCronTask.  The cronAction() method is overridden to perform a different action.  The cron is executed using the alternative runCron() that accepts a Class object.  It is that Class that will be instantiated instead of the one defined in the CRONTASKDEF table.


      public static class DemoCron extends PMWoGenCronTask {  
           @Override  
           public void cronAction() {  
                throw new RuntimeException("Stopped!");  
           }            
      } 

The full source is available in CronTaskDemo3Test.java

As a safety precaution,  the CronTaskTestHarness makes sure that the class passed in the first parameter is a subclass of the class defined in CRONTASKDEF.

If the DemoCron is changed to extend from PMWoGenCronTask, the test will fail with a message that "Test class must be a subclass of com.ibm.tivoli.maximo.report.kpi.KPIHistoryCleanupCronTask."  This will catch situations where the cron class has changed in the database or the developer makes a mistake in the class definition.

No comments:

Post a Comment