+ Start a Discussion
devforce_111devforce_111 

Help with Test class

HI,

 

Below is the class and test class. It fine in UAT and gives  no errors but iam not able to deploy it into production as it gives error as  System.LimitException:Too many Query locator rows:10001

 

global class Visibility_Batch_BankAccount implements Database.Batchable<sObject> , Database.Stateful {
String query;
private Visibility_Utility vu;

global Database.QueryLocator start(Database.BatchableContext BC){
vu = new Visibility_Utility();

Visibility_Batch_Base vbb = new Visibility_Batch_Base('Bank_Account__c');
List<Integration_Info__c> intInfoList = [Select Last_Run_Time__c, Previous_Last_Run_Time__c from Integration_Info__c limit 1];
DateTime lastRunTime = intInfoList[0].Last_Run_Time__c;
DateTime PreviousLastRunTime = intInfoList[0].Previous_Last_Run_Time__c;

query = vbb.getQueryString();
return database.getQueryLocator(query);
}

global void execute(Database.BatchableContext BC, List<sObject> scope){
vu.createShare('Bank_Account__c',scope);
}

global void finish(Database.BatchableContext BC){

}
}

 

and the test class is

 

@isTest
private class Visibility_Batch_BankAccount_Test{

static testMethod void Visibility_Batch_BankAccountTest(){
Visibility_Batch_BankAccount visBctBnkAcc = new Visibility_Batch_BankAccount();
Integration_Info__c ii = new Integration_Info__c();
ii.Previous_Last_Run_Time__c = System.Now().addMinutes(-1);
ii.Last_Run_Time__c = system.Now();
insert ii;


Bank_Account__c testBnkAcc = new Bank_Account__c(Name='testName');
List<Bank_Account__c> lstBnkAcc = new List<Bank_Account__c>();
lstBnkAcc.add(testBnkAcc);
insert lstBnkAcc;
Test.startTest();
visBctBnkAcc.start(null);
visBctBnkAcc.execute(null,lstBnkAcc);
visBctBnkAcc.finish(null);
Test.stopTest();
}
}

 

Thanks

Best Answer chosen by Admin (Salesforce Developers) 
MattLacey.ax1065MattLacey.ax1065

Sure, System.IsRunningTest() simply returns true if the code is being executed as a test as opposed to being executed in a legitimate context by a user, so if you modify your handler class as follows you should be good to go:

 

public class IntergrationInfoHandler{
    public static void initiateBatches(){
        Visibility_Batch_Group vbg = new Visibility_Batch_Group();
        Visibility_Batch_Party vbp = new Visibility_Batch_Party();
        Visibility_Batch_BankAccount vbb = new Visibility_Batch_BankAccount();
        Visibility_Batch_RelationshipGroup vbrg = new Visibility_Batch_RelationshipGroup();
 

        if(!System.IsRunningTest()){       

                DataBase.ExecuteBatch(vbg);
                DataBase.ExecuteBatch(vbp);
                DataBase.ExecuteBatch(vbb);
                DataBase.ExecuteBatch(vbrg);
        }
    }
}

 

 

 

All Answers

MattLacey.ax1065MattLacey.ax1065

You should never rely on data from the database for your testmethods, instead be sure to always insert a record that your queries will find, and also use Test.IsRunningTest to determine if the code is being fired by a test method, if so you can then put a 'limit 1' or similar onto your query to ensure you don't get back masses of data.

 

In your case I would suggest that the query being returned by vbb.getQueryString() doesn't have a limit, and in your production environment you've got more than 10,000 rows of data in the Bank_Account__c object (assuming that's an object!) whereas in UAT you have less than 10,000.

 

Also be aware that you can only invoke the execute method once inside a batchable class in a test method so ensure the limit you use is smaller than the batch size (200 by default I believe). 

devforce_111devforce_111

Hi Matt

 

I changed my test class as below but its still giving errors as 

 

Failure Message: "System.UnexpectedException: No more than one executeBatch can be called from within a testmethod. Please make sure the iterable returned from your start method matches the batch size, resulting in one executeBatch invocation.", Failure Stack Trace: "External entry point"

 

Not really sure what to do!!!!!


@isTest
private class Visibility_Batch_BankAccount_Test{

Profile p = [select id from profile where name='Rep Officer'];
User u = new User(alias = 'standt', email='standarduser@testorg.com',emailencodingkey='UTF-8', lastname='Testing',
languagelocalekey='en_US',localesidkey='en_US', profileid = p.Id,timezonesidkey='America/Los_Angeles',
username='stanr@testorg.com');
insert u;

static testMethod void Visibility_Batch_BankAccountTest(){
Visibility_Batch_BankAccount visBctBnkAcc = new Visibility_Batch_BankAccount();
Integration_Info__c ii = new Integration_Info__c();
ii.Previous_Last_Run_Time__c = System.Now().addMinutes(-1);
ii.Last_Run_Time__c = system.Now();
insert ii;


Bank_Account__c testBnkAcc = new Bank_Account__c(Name='testName');
List<Bank_Account__c> lstBnkAcc = new List<Bank_Account__c>();
lstBnkAcc.add(testBnkAcc);
insert lstBnkAcc;
Test.startTest();
System.runAs(u){
visBctBnkAcc.query = 'SELECT Id, Rep_Officer_Code__c, Account_Officer_Code__c, Office_Code__c FROM Bank_Account__c LIMIT 200';
visBctBnkAcc.start(null);
ID batchprocessid = Database.executeBatch(visBctBnkAcc);
visBctBnkAcc.finish(null);
}
Test.stopTest();
}
}

 

And by the way we do same data load both in UAT and Production daily. so the number of records are almost same in number in both UAT and Production. So not sure why its giving error in production and running fine in UAT.

 

Thanks

MattLacey.ax1065MattLacey.ax1065

Hmmm, I can only see the one invocation of executeBatch, do you have another test method calling this one or anything? Or perhaps a trigger on insert of one of the objects that might be firing a batch?

devforce_111devforce_111

Yes, I have 3 more test classes in similar way for objects named Parties (Accounts), Group__c, Relationship_Group__c and i have written the test classes as i wrote for Bank_Account__c object

devforce_111devforce_111

And even i have trigger written on Integration_Info__c object . On the insert of the record into that object , the trigger fires and the batch apex classes runs

MattLacey.ax1065MattLacey.ax1065

Ah ha!

 

The first part is fine, as they're separate test methods so won't impact each other. The one in the trigger is where you'll be coming unstuck.

 

My suggestion would be to call System.IsRunningTest() in the trigger, if it returns true then don't execute the batch there — that way when you try to invoke it later on in your test method it'll be for the first time and you should avoid the error.

 

Matt

 

devforce_111devforce_111

Here is my trigger code

 

trigger runVisibilityBatch on Integration_Info__c(After insert, After update){
    if(trigger.isAfter){
        IntergrationInfoHandler.initiateBatches();
    }
}

 

and the Handler class for that is 

 

public class IntergrationInfoHandler{
    public static void initiateBatches(){
        Visibility_Batch_Group vbg = new Visibility_Batch_Group();
        Visibility_Batch_Party vbp = new Visibility_Batch_Party();
        Visibility_Batch_BankAccount vbb = new Visibility_Batch_BankAccount();
        Visibility_Batch_RelationshipGroup vbrg = new Visibility_Batch_RelationshipGroup();
        
        DataBase.ExecuteBatch(vbg);
        DataBase.ExecuteBatch(vbp);
        DataBase.ExecuteBatch(vbb);
        DataBase.ExecuteBatch(vbrg);
        
    }
}

 

I dont really know abt System.isRunningTest(). can u pls thow some more light on that or can u pls tell me where exactly shud i use that in my code

 

Thanks

MattLacey.ax1065MattLacey.ax1065

Sure, System.IsRunningTest() simply returns true if the code is being executed as a test as opposed to being executed in a legitimate context by a user, so if you modify your handler class as follows you should be good to go:

 

public class IntergrationInfoHandler{
    public static void initiateBatches(){
        Visibility_Batch_Group vbg = new Visibility_Batch_Group();
        Visibility_Batch_Party vbp = new Visibility_Batch_Party();
        Visibility_Batch_BankAccount vbb = new Visibility_Batch_BankAccount();
        Visibility_Batch_RelationshipGroup vbrg = new Visibility_Batch_RelationshipGroup();
 

        if(!System.IsRunningTest()){       

                DataBase.ExecuteBatch(vbg);
                DataBase.ExecuteBatch(vbp);
                DataBase.ExecuteBatch(vbb);
                DataBase.ExecuteBatch(vbrg);
        }
    }
}

 

 

 

This was selected as the best answer
devforce_111devforce_111

Hi Matt, 

 

Thanks for the Reply. But its saying system.IsRunningTest() method doesnot not exist. Instead i worte Test.IsRunningTest() and the class got saved but still its giving the error as 

 

Failure Message: "System.UnexpectedException: No more than one executeBatch can be called from within a testmethod. Please make sure the iterable returned from your start method matches the batch size, resulting in one executeBatch invocation."

 

just to make u clear , Here is all my code

 

Apex cbatch class for Bank_Account__c

 

global class Visibility_Batch_BankAccount implements Database.Batchable<sObject> , Database.Stateful {
    global String query;
    private Visibility_Utility vu;

    global Database.QueryLocator start(Database.BatchableContext BC){
        vu = new Visibility_Utility();
        
        Visibility_Batch_Base vbb = new Visibility_Batch_Base('Bank_Account__c');
        List<Integration_Info__c> intInfoList = [Select Last_Run_Time__c, Previous_Last_Run_Time__c from Integration_Info__c limit 1];
        DateTime lastRunTime = intInfoList[0].Last_Run_Time__c;
        DateTime PreviousLastRunTime = intInfoList[0].Previous_Last_Run_Time__c;

        query = vbb.getQueryString();
        return database.getQueryLocator(query);
       
    }

    global void execute(Database.BatchableContext BC, List<sObject> scope){   
        vu.createShare('Bank_Account__c',scope);
    }
     

    global void finish(Database.BatchableContext BC){

    }
}

Test class for it is 

@isTest
private class Visibility_Batch_BankAccount_Test{


static testMethod void Visibility_Batch_BankAccountTest(){
Visibility_Batch_BankAccount visBctBnkAcc = new Visibility_Batch_BankAccount();
Integration_Info__c ii = new Integration_Info__c();
ii.Previous_Last_Run_Time__c = System.Now().addMinutes(-1);
ii.Last_Run_Time__c = system.Now();
insert ii;

Profile p = [select id from profile where name='Rep Officer' LIMIT 1];
 User u = new User(alias = 'standt', email='standarduser@testorg.com',emailencodingkey='UTF-8', lastname='Testing',
  languagelocalekey='en_US',localesidkey='en_US', profileid = p.Id,timezonesidkey='America/Los_Angeles',
   username='stanr@testorg.com');
   insert u;

Bank_Account__c testBnkAcc = new Bank_Account__c(Name='testName');
List<Bank_Account__c> lstBnkAcc = new List<Bank_Account__c>();
lstBnkAcc.add(testBnkAcc);
insert lstBnkAcc;
Test.startTest();
System.runAs(u){
visBctBnkAcc.query = 'SELECT Id, Rep_Officer_Code__c, Account_Officer_Code__c, Office_Code__c FROM Bank_Account__c LIMIT 1';
visBctBnkAcc.start(null);
ID batchprocessid = Database.executeBatch(visBctBnkAcc);
visBctBnkAcc.finish(null);
}
Test.stopTest();
}
}

 

and the handlet class for the trigger is

public class IntergrationInfoHandler{
    public static void initiateBatches(){
        Visibility_Batch_Group vbg = new Visibility_Batch_Group();
        Visibility_Batch_Party vbp = new Visibility_Batch_Party();
        Visibility_Batch_BankAccount vbb = new Visibility_Batch_BankAccount();
        Visibility_Batch_RelationshipGroup vbrg = new Visibility_Batch_RelationshipGroup();
        
         if(!Test.IsRunningTest()){ 
        DataBase.ExecuteBatch(vbg);
        DataBase.ExecuteBatch(vbp);
        DataBase.ExecuteBatch(vbb);
        DataBase.ExecuteBatch(vbrg);
        
   }
    }
}

 

 

I think iam lost now. Not really sure what exactly to do. Please help me on this its very urgent as im unable to deploy anything to prodution because the trigger has 0% code coverage

 

Thanks

 

 

 

MattLacey.ax1065MattLacey.ax1065

Apologies for that, I always forget which of those classes it belongs to!

 

Code should be ok now, I'd say the next step is to run through the debug logs generated when you test the deployment, see if you can find the locations where database.executeBatch() is being invoked, and then follow back to see where else you may need a switch to prevent automatic execution from a trigger or similar. 

MattLacey.ax1065MattLacey.ax1065

Actually, looking at the error you've posted it would suggest that it uses the same message for calling executeBatch as it does for multiple invocations of the execute() method in your batch apex class.

 

You're using the default execute which expects a batch size of 200 records and you're specifying 'LIMIT 1' so that shouldn't be a problem. I'm check all of your other triggers etc. and the logs to see what else might be firing the batch. If you remove the call to execute from your test method does the test pass?

 

 

devforce_111devforce_111

Matt

 

The test classes passed and was able to deploy to production. However iam getting only 60% of code coverage for the classes but got 100% coverage for the trigger. So i guess trigger coverage matters the most for deployment.

 

So Thankyou so much

MattLacey.ax1065MattLacey.ax1065

The 75% requirement is an average across all of your code, if I were you I'd now run the tests in prod and see if you can work out what's causing the batch to be executed (without your explicit line there) — the higher you get your coverage the less pain you'll have during future deployments!