[SalesForce] Error: Too many query locator rows: 10001

I have batchable apex that is throwing the Too Many Query Locator Rows error:

Global Class FocusDomainBatch implements Database.Batchable<sObject>, Database.allowsCallouts
    {
        global Database.querylocator start(Database.BatchableContext BC)
        {
            String query = 'Select id,name from Domain_Stats__c';
            return Database.getQueryLocator(query);    
        }


global void execute(Database.BatchableContext BC, List<sObject> scope)
    {
        try
        {
           List <Focus_Domain_Stats__c> allDomains = scope;          
           List <string> web = new List <string>();

There are more than 10k Domain_Stats__c records, but I was under the impression that in batchable that was ok?

It is being called by :

Public Class FocusDomainStatsSchedulable implements Schedulable 
{
    Public void execute(SchedulableContext SC)
    {
        try
        {
           if(!Test.isRunningTest())
           {
                FocusDomainBatch fd = new FocusDomainBatch();
                Database.executeBatch(fd,5);
           }

         } 
         Catch(exception e)
         {
             throw e;
         }
    }
}

Here is the test class that is failing:

@IsTest(seealldata=true)

    Public Class TestFocusDomainBatch
    {

    Static testMethod void TestFocusDomainBatch ()
    {               

        Test.StartTest();

        Test.setMock(HttpCalloutMock.class, new MockHttpResponseGenerator1());
        FocusDomainBatch fb = new FocusDomainBatch(); 
        Date lastMonth = Date.Today().addMonths(-6);
        fb.start(null); //Failing here
        fb.finish(null);
        //List<Focus_Product__c> fpContacts = [select id,contact__c from Focus_Product__c where createddate > :lastmonth and contact__C <> null limit 1];
        //List<Focus_Product__c> fpLeads = [select id,contact__c from Focus_Product__c where createddate > :lastmonth and contact__C <> null limit 1];        

        List <Lead> allLeads = [Select Id, name, HG_Focus_Sign_Up_Date__c, website from Lead where createddate > :lastMonth and isConverted = false and Focus_Sign_Up_Date__c <> null limit 1];
        List <Contact> allContacts = [Select Id, name, HG_Focus_Sign_Up_Date__c, account.website from contact where createddate > :lastMonth and Focus_Sign_Up_Date__c <> null limit 1]; 
        List<string> webs = new List<string>();
        if(allLeads.size() > 0)
            webs.add(allLeads[0].webSite);
        if(allContacts.size() > 0)
            webs.add(allContacts[0].account.webSite);
        //database.executebatch(fb);
        fb.execute(null,[Select id,name, First_user_sign_up_date__c, Total_Users__c, New_Users_In_Last_Month__c, Avg_Fvrt_Pro_Per_User__c, Users_with_zero_fvrts__c, Users_with_2_or_less_fvrts__c, Average_daily_queries__c, Average_monthly_queries__c, Total_current_month_queries__c, Total_Queries__c from Focus_Domain_Stats__c where name in :webs]);
        Test.StopTest();

    }

Best Answer

The way you should really test a batch is by calling Database.executeBatch. Don't call start and execute directly.

You should also test without SeeAllData. You should never use SeeAllData unless it's your only choice. There are many reasons why it's bad practice to unit test against existing data. Unit tests will not perform the same in your sandboxes as your staging/production environments. Your tests will run significantly slower. You have a lot less control over what you're actually testing.

Take a look at Using Batch Apex (specifically the Testing Batch Apex section). You need to make sure you get at most one execute block, which effectively limits you to 200 records.

static testMethod void testMyBatch()
{
    // setup data for your batch to process
    // make sure it's less than 200 records
    // you can only call the execute method once!

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

    // assert on results
}