Hin und wieder kommt es vor, dass viele Daten im Hintergrund aktualisiert werden müssen. Es ist keine Zauberei, einen Batch dafür zu schreiben. Viel mehr kommt es auf die Technik an. Schließlich muss jeder Batch auch getestet werden. Da Batches asynchron laufen, also zeitversetzt, und nicht unmittelbar nach dem Start, wird die Überprüfung der Testergebnisse nicht einfach sein.
Daher ist es empfehlenswert, die komplette Logik in eine weitere Klasse auszulagern. So können die einzelnen Methoden und Funktionen dieser Klasse sowohl vom Batch benutzt, als auch im Testlauf geprüft werden.
Schematisch dargestellt sieht der Aufbau wie folgt aus:
Batch - Löschen von Daten (f42_Batch_DeleteData)
Daher ist es empfehlenswert, die komplette Logik in eine weitere Klasse auszulagern. So können die einzelnen Methoden und Funktionen dieser Klasse sowohl vom Batch benutzt, als auch im Testlauf geprüft werden.
Schematisch dargestellt sieht der Aufbau wie folgt aus:
Batch - Löschen von Daten (f42_Batch_DeleteData)
global
class
f42_Batch_DeleteData implements
Database.Stateful, Database.Batchable<SObject>, Schedulable{
public
f42_Batch_DeleteDataHelper batchHelper;
public
String soql;
/* Constructor */
/*********************/
public
f42_Batch_DeleteData(){
batchHelper
= new
f42_Batch_DeleteDataHelper();
}
/* execute SchedulableContext */
/******************************/
global
void
execute(SchedulableContext SC) {
for(String
s : batchHelper.buildSearchStrings()){
f42_Batch_DeleteData
b = new
f42_Batch_DeleteData();
b.soql
= s;
Database.executeBatch(b);
}
}
/*
start */
/*********************/
global
Database.QueryLocator start(Database.BatchableContext bc){
return
Database.getQueryLocator(soql);
}
/*
execute */
/*********************/
global
void
execute(Database.BatchableContext bc, List<sObject>
lstObjects){
batchHelper.Batch_Execute(lstObjects);
}
/*
finish */
/*********************/
global
void
finish(Database.BatchableContext bc){
batchHelper.Batch_Finish();
}
}
Helper (f42_Batch_DeleteDataHelper)
public without sharing class f42_Batch_DeleteDataHelper {
private list<String> lstSearchObjects;
public DateTime dtToday;
/* Constructor */
/*********************/
public f42_Batch_DeleteDataHelper(){
// list with objects to find and delete
lstSearchObjects = new list<String>();
lstSearchObjects.add('Object1__c'); // Finde und lösche Object1
lstSearchObjects.add('Object2__c'); // Finde und lösche Object2
dtToday = Date.today();
}
/****************************
Batch_Execute
*/
public void Batch_Execute(List<sObject> lstObjects){
if( !(lstObjects == null || lstObjects.isEmpty())){
//try {
delete lstObjects;
//} catch (DmlException e) {
// Process exception here
//}
}
}
/****************************
Batch_Finish
*/
public void Batch_Finish(){
// %
}
/* BuildSearchString() */
/********************/
public list<String> buildSearchStrings(){
// WHERE part of SOQL
String wherePart = 'CreatedDate < ' + dtToday.format('yyyy-MM-dd\'T\'HH:mm:ss.000\'Z\'');
// build search string
list<String> lstSearch = new list<String>();
// build soql search string
for(String s :lstSearchObjects){
lstSearch.add('SELECT Id FROM ' + s + ' WHERE ' + wherePart);
}
return lstSearch;
}
}
Test (f42_Test_Batch_DeleteData)
@isTest
private class f42_Test_Batch_DeleteData {
private static Account acc;
private static list<Object1__c> lstObj1 = new list<Object1__c>();
private static list<Object2__c> lstObj2 = new list<Object2__c>();
private static list<f42_Order_Positions__c> lstPositions = new list<f42_Order_Positions__c>();
/*********************
test_BatchDeleteData
just to arrive more test coverage for batch class*/
static testMethod void test_BatchDeleteData() {
createTestData();
Test.startTest();
f42_Batch_DeleteData newBatch = new f42_Batch_DeleteData();
newBatch.execute(null, lstObj1);
Test.stopTest();
}
/*********************
test batch execute method */
static testMethod void testBatchMethod_Execute() {
createTestData();
Test.startTest();
f42_Batch_DeleteDataHelper batchHelper = new f42_Batch_DeleteDataHelper();
batchHelper.dtToday = date.today().addDays(1);
//EXECUTE
for(String s : batchHelper.buildSearchStrings()){
list<sObject> lstSobjects = database.query(s);
batchHelper.Batch_Execute(lstSobjects);
}
//check
list<Object1__c> lst1 = [select id from Object1__c];
list<Object2__c> lst2 = [select id from Object2__c];
system.assert(lst1.isEmpty());
system.assert(lst2.isEmpty());
Test.stopTest();
}
/*********************
test batch finish method */
static testMethod void testBatchMethod_Finish() {
Test.startTest();
f42_Batch_DeleteDataHelper batchHelper = new f42_Batch_DeleteDataHelper();
//FINISH
batchHelper.Batch_Finish();
Test.stopTest();
}
/*********************
test for schedule batch */
static testMethod void testScheduleForBatch(){
Test.startTest();
Date dtToday = Date.today();
DateTime dtNextRun = DateTime.newInstance(dtToday.year(), dtToday.month(), dtToday.day(), 1, 0, 0);
dtNextRun = dtNextRun.addDays(1);
String ss = String.valueOf(dtNextRun.second());
String mm = String.valueOf(dtNextRun.minute());
String hh = String.valueOf(dtNextRun.hour());
String d = String.valueOf(dtNextRun.day());
String m = String.valueOf(dtNextRun.month());
String y = String.valueOf(dtNextRun.year());
String jobName = 'TEST Batch: ' + dtNextRun.formatLong();
String ScheduleParam = '00' + ' ' + mm + ' ' + hh + ' ' + d + ' ' + m + ' ? ' + y;
//Start Scheduled Job
String jobId = System.schedule(jobName, ScheduleParam, new f42_Batch_DeleteData());
//Get the information from the CronTrigger API object
CronTrigger ct = [SELECT Id, CronExpression, TimesTriggered, NextFireTime FROM CronTrigger WHERE id = :jobId];
// Verify the expressions are the same
System.assertEquals(ScheduleParam, ct.CronExpression);
// Verify the job has not run
System.assertEquals(0, ct.TimesTriggered);
Test.stopTest();
}
/******************
Test Data
**/
private static void createTestData(){
Integer maxNumber = 10;
// ACCOUNT
acc = f42_TestDataGenerator.createTestAccount(1, true);
system.assertnotequals(null, acc.id);
// OBJECT 1
for(Integer i = 1; i<=maxNumber; i++){
lstObj1.add(f42_TestDataGenerator.createTestObject1(i, acc.Id, false));
}
insert lstObj1;
system.assertEquals(maxNumber, lstObj1.size());
// OBJECT 2
for(Integer i = 1; i<=maxNumber; i++){
lstObj2.add(f42_TestDataGenerator.createTestObject2(i, acc.Id, false));
}
insert lstObj2;
system.assertEquals(maxNumber, lstObj2.size());
}
}
Testdata Generator (f42_TestDataGenerator)
Testdata Generator (f42_TestDataGenerator)
public without sharing class f42_TestDataGenerator {
//Account
public
static
Account
createTestAccount(Double i, Boolean insertObject){
Account
a = new
Account();
a.Name
= 'Test ' +
i;
a.BillingStreet
= 'Musterstr.';
a.BillingPostalCode
= '81671';
a.BillingCity
= 'München';
a.BillingCountry
= 'Germany';
if(insertObject)
insert
a;
return
a;
}
//Object1
public static Object1__c createTestObject1(Double i, Boolean insertObject){
Object1__c obj = new Object1__c();
obj.Name = 'Test ' + i;
if(insertObject)
insert obj;
return obj;
}
//Object2
public static Object2__c createTestObject2(Double i, Boolean insertObject){
Object2__c obj = new Object2__c();
obj.Name = 'Test ' + i;
if(insertObject)
insert obj;
return obj;
}
}
Kommentare
Kommentar veröffentlichen