2

I am doing the challenge for 'Asynchronous Apex-->Future Method' module and have written following apex classes:

public class AccountProcessor {
    @future
    public static void countContacts (List<ID> accountIDs ){
        List<Account> accounts = [select account.name, account.Number_of_Contacts__c from account where ID IN :accountIDs];
        for (Account acct : accounts){
            Integer count = [SELECT COUNT() FROM Contact, Contact.Account where Account.ID = :acct.ID];
            acct.Number_of_Contacts__c = count;
            System.debug('Count of Contact: ' + count + ' for accountID ' + acct.ID);    
        }
        update accounts;
        System.debug('Accounts: ' + accounts);
    }
}

@IsTest
public class AccountProcessorTest {
    @IsTest
    private static void testCountContacts() {
        List<ID> accountIDs = new List<ID> {'001f400000NIxzUAAT', '001f400000NIxzXAAT'};
        Test.startTest();
        AccountProcessor.countContacts(accountIDs);
        Test.stopTest();
        for (ID acctID : accountIDs){
        Integer count = [SELECT COUNT() FROM Contact, Contact.Account where Account.ID = :acctID];
            system.debug('Count: ' + count);
            if (acctID == '001f400000NIxzUAAT'){
                System.assertEquals(2, count);
            }
        }

    }
}

In the test class, assertion is failing as no records found from select query, but when I run from anonymous block the AccountProcessor runs successfully and count for the account with ID: 001f400000NIxzUAAT prints 2.

Please suggest.

1
  • Welcome to SFSE, please use CTRL+K for formatting your code block next time onward for readability. May 10 '18 at 4:26
1

Your main class contains SOQL query in for loop, so follow the Apex Code Best Practices and I have written this kind of logic for you using Aggregate query.

public class AccountProcessor {
    @future
    public static void countContacts (List<ID> accountIDs ){

        List<AggregateResult> lstContact = [SELECT AccountId, COUNT(Id) idCount FROM Contact
                            WHERE AccountId IN:accountIDs
                            GROUP By AccountId];

        List<Account> lstAccount = new List<Account>();
        for(AggregateResult result:lstContact)
        {
            Account acct = new Account(Id= (String) result.get('AccountId'), 
                            Number_of_Contacts__c = (Integer) result.get('idCount'));

            lstAccount.add(acct);
        }
        update lstAccount;
        System.debug('Accounts: ' + lstAccount);

    }
}

Also, follow Testing Best Practices to create your own test data for testing.

Test Class will be like this. since you are updating Number_of_Contacts__c in the future method, so better to assert that value, rather than counting contacts separately for assertion.

@IsTest
public class AccountProcessorTest {
    @IsTest
    private static void testCountContacts() {

        Account acct = new Account(Name = 'Test1');
        insert acct;

        Contact con = new Contact(LastName = 'LastName', AccountId =acct.Id);
        insert con;

        List<ID> accountIDs = new List<ID>();
        accountIDs.add(acct.Id);

        Test.startTest();
        AccountProcessor.countContacts(accountIDs);
        Test.stopTest();

        Account acctObj = [SELECT Number_of_Contacts__c FROM Account WHERE Id=:acct.Id];
        System.assertEquals(1, acctObj.Number_of_Contacts__c);
    }
}
1
  • I am beginner in apex and was struggling last night. Thanks for your help, Jayant & Santanu.
    – madajee
    May 10 '18 at 16:59
4

You will not get any results from the query you have in your test class.

And the reason being, you are trying to use ids of existing records in your organization within your test class with this statement:

List<ID> accountIDs = new List<ID> {'001f400000NIxzUAAT', '001f400000NIxzXAAT'};

Existing records cannot be accessed in test class until you use @isTest(SeeAllData=true) annotation on your test class. Refer to the excerpt from the documentation:

Annotate your test class or test method with IsTest(SeeAllData=true) to open up data access to records in your organization.

To avoid scenarios like this, its always recommended that you create all test data in your test class for any unit testing.

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.