2

I have one batch class which has almost 6k records.I have written test class for the same.But i am getting error saying

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.

I am creating one record for which i wanted test class to run.But i can see in background org data is being running for batch jobs. I dont see batch job is not running for only one record which i inserted in test class.

Do I need to create a constructor which can have one parameter as user and then I can pass one user record inside test class.I am not sure why it is running batch jobs for all org data.Below is my batch class:

Batch class:

global Lighting_DeactivateUserBatch()
{
    this(getFrozenUserIds());
}
@TestVisible Lighting_DeactivateUserBatch(Set<Id> frozenUserIds)
{
    this.frozenUserIds = frozenUserIds;
}
public static Set<Id> getFrozenUserIds()
{
    List<UserLogin> frozenUserList;
    List<ID> frozenIDList = new List<ID>();
    Set<ID> setRecordOwner = new set<ID>();
    // generate collection
    frozenUserList = [Select UserID from UserLogin where isFrozen=true];
    for(userlogin frozen : frozenUserList) {
        frozenIDList.add(frozen.UserID);
    }
    AggregateResult[] ownerListOpp = [SELECT OwnerID Owner FROM Opportunity group by OwnerID];
    AggregateResult[] ownerListAcc = [SELECT OwnerID Owner FROM Account group by OwnerID];
    AggregateResult[] ownerListCon = [SELECT OwnerID Owner FROM Contact group by OwnerID];
    AggregateResult[] ownerListLead = [SELECT OwnerID Owner FROM Lead group by OwnerID];
    ownerListOpp.addall(ownerListACC);
    ownerListOpp.addall(ownerListCon);
    ownerListOpp.addall(ownerListLead);
    for(AggregateResult agg : ownerListOpp) {
        setRecordOwner.add((ID) agg.get('Owner'));
    }
    return setRecordOwner;
}

global List<User> start(Database.BatchableContext BC){

    //user u = new user(ID='00524000001IFILAA4');
    //List<user> queryForEmailAlert = [Select ID, Email, LastLoginDate ,createddate,Reactivation_Date__c,isportalenabled,TEST_CREATED_DATE__C,TEST_LOGIN_DATE__C from User where Functional_System_User__c=false and isActive =true and ID=:U.Id AND ID not in :frozenIDList ORDER BY TEST_LOGIN_DATE__C ASC NULLS LAST];
    List<user> queryForEmailAlert = [Select ID, Email, LastLoginDate ,createddate,Reactivation_Date__c,isportalenabled,TEST_CREATED_DATE__C,TEST_LOGIN_DATE__C from User where Functional_System_User__c=false and isActive =true AND ID not in :frozenIDList ORDER BY TEST_LOGIN_DATE__C ASC NULLS LAST];
    System.debug('users applicable for batch deactivation ::::: '+queryForEmailAlert);
    return (queryForEmailAlert);
    //return (u);
}

global void execute(Database.BatchableContext BC, List<sObject> scope){
    Set<ID> userOwnerSet = new Set<ID>();
    Set<ID> userDeactSet = new Set<ID>();
    List<User> listAllUser = (List<User>) scope;
 .....

Test class:

      @isTest
public class Lighting_DeactivateUserBatch_Test {

    public static testmethod void testScenario3() {

    Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
    User u1 = new User(Alias = 'standt1',Country='United Kingdom',Code_1_ID__c='123abc45',Email='demo1@randomdemodomain.com',Functional_System_User__c=True, EmailEncodingKey='UTF-8', LastName='Testing', LanguageLocaleKey='en_US',LocaleSidKey='en_US',ProfileId = p.Id,TimeZoneSidKey='America/Los_Angeles', UserName='demo1@andomdemodomain.com');
    insert u1;
    system.debug('User1@@@@@@'+ u1);
    Datetime newUserAlertDate = Datetime.now().addDays(-23);
    System.debug('value of new date ::::: '+newUserAlertDate);
    Test.setCreatedDate(u1.Id, newUserAlertDate);
    User u = [select id,Name,createddate,Functional_System_User__c,lastlogindate,isActive from user where id=:u1.id];
    MO_Inactive_Users__c dateParam = new MO_Inactive_Users__c(Name='Date Param',Grace_Period__c=5,Inactivation_Days_to_Deactivate__c=90,Inactivation_Days_to_Deactivate_New_User__c=30,Inactivation_Days_to_Notify__c=83,Inactivation_days_to_Notify_New_User__c=23);

        insert dateParam;
        System.debug('value of test user ::::: '+u);
        Test.startTest();
        Set<Id> testBlacklist = new Set<Id>();
        for (User user : [SELECT Id FROM User WHERE IsActive = true AND Functional_System_User__c = false]){
        testBlacklist.add(user.Id);

        }
        system.debug('testBlacklist-isFrozen@@@@@'+ testBlacklist); 

            Database.executeBatch(new Lighting_DeactivateUserBatch(testBlacklist));
        Test.stopTest();
    //userlogin US = Select id,isfrozen from userlogin where userid=u1.id;
    //system.debug('User1-isFrozen@@@@@'+ US.IsFrozen)//
    //User u2 = new User(Alias = 'standt2',Country='United Kingdom',Code_1_ID__c='6789xyz0',Email='demo2@randomdemodomain.com',EmailEncodingKey='UTF-8', LastName='Testing', LanguageLocaleKey='en_US',LocaleSidKey='en_US', ProfileId = p.Id,TimeZoneSidKey='America/Los_Angeles', UserName='demo2@andomdemodomain.com');
    //insert u2;    
    //system.debug('User2@@@@@@'+ u2);
    }

}
  • How to restrict test class batch run for only one record which i am inserting in test class. – Jack vardy Jan 29 '16 at 14:47
  • I can see in the logs i am getting org data while running test class – Jack vardy Jan 29 '16 at 16:26
  • Make sure your API Version >= 24. Prior to that the default for SeeAllData was true. You could also instead of testMethod use @IsTest(SeeAllData=false) – Adrian Larson Jan 29 '16 at 16:45
  • Robert.. few objects like userlogin, profiles records can be accessible in test class. What you can do modify your batch constructor ( create two constructor one for batch and another for test) and pass list of record in that constructor.. and use that record in further process – Ratan Paul Jan 29 '16 at 16:56
  • Robert.. few objects like userlogin, profiles records can be accessible in test class. What you can do modify your batch constructor ( create two constructor one for batch and another for test) and pass list of record in that constructor.. and use that record in further process – Ratan Paul Jan 29 '16 at 16:57
1

You can decouple the data fairly simply in this case with a @TestVisible constructor:

global MyBatch()
{
    this(getFrozenUserIds());
}
@TestVisible MyBatch(Set<Id> frozenUserIds)
{
    this.frozenUserIds = frozenUserIds;
}
public static Set<Id> getFrozenUserIds()
{
    // generate collection
}

Now in your test, when you want to execute the batch, construct it with your own Set<Id>:

Set<Id> testBlacklist = new Set<Id>();
for (User user : [
    SELECT Id FROM User WHERE IsActive = true
    AND Functional_System_User__c = false
]) testBlacklist.add(user.Id);

Test.startTest();
    Database.executeBatch(new MyBatch(testBlacklist));
Test.stopTest();

// assert stuff

Note that you can still test the empty constructor as well, basically making sure it is getting the correct blacklist when you do not specify one. Since this list is quite large, as you have found, you will not be able to run the batch with it.

| improve this answer | |
0

In your test, you could modify all users in order to the query condition is not satisfied, then create your test data.

This should work, but maybe it is not the best solution.

| improve this answer | |
  • Problem for me is all org data is getting into scope rather than test data which i am inserting.I thought in test class,only test data will be executed by batch class execute method. – Jack vardy Jan 29 '16 at 16:33
  • Real data are not used in tests, excepting some of them. You can see the list here developer.salesforce.com/docs/atlas.en-us.apexcode.meta/… And yes, users and in test scope. – Javier Vazquez Jan 29 '16 at 16:36
  • So how to avoid this error as per my test class.What shall i improve ? – Jack vardy Jan 29 '16 at 16:40
  • Add the next code before create your user (the code is not tested). List<UserLogin> userLoginList = [Select UserID, isFrozen from UserLogin where isFrozen=true]; for(UserLogin frozen : userLoginList) { frozen.isFrozen = false; } update userLoginList; – Javier Vazquez Jan 29 '16 at 16:45
  • Add the next code before create your user? – Jack vardy Jan 29 '16 at 16:47
0

I got what was the root cause of issue.I was getting more than 6k org data from start method query.As per test class of batch,Batch must run only once as per governor limit.So now i have restricted no. of user records specific to test class by using Test.IsRunningTest() context.I have added limit of 100 specific for test class.

Global variable:
global list<user> queryForEmailAlert;

start() Method:-

global List<User> start(Database.BatchableContext BC){

        if(Test.isRunningTest()){
        queryForEmailAlert = [Select ID, Email, LastLoginDate ,createddate,Reactivation_Date__c,isportalenabled,TEST_CREATED_DATE__C,TEST_LOGIN_DATE__C from User where Functional_System_User__c=false and isActive =true AND ID not in :frozenIDList ORDER BY TEST_LOGIN_DATE__C ASC NULLS LAST limit 100];
        }else{
        queryForEmailAlert = [Select ID, Email, LastLoginDate ,createddate,Reactivation_Date__c,isportalenabled,TEST_CREATED_DATE__C,TEST_LOGIN_DATE__C from User where Functional_System_User__c=false and isActive =true AND ID not in :frozenIDList ORDER BY TEST_LOGIN_DATE__C ASC NULLS LAST];
        }
        System.debug('users applicable for batch deactivation ::::: '+queryForEmailAlert);
        return (queryForEmailAlert);

    }
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.