2

I need some basic Unit Test writing assistance.

My method just runs a SOQL query to filter a contact list for service cloud. What's the best way to test it?

Here is the class:

public class ContactsListController{
    public ContactsListController(ApexPages.StandardController stdController) {
        this.acct = (Account)stdController.getRecord();
    }

    private final Account acct;


    public List<Contact> getContacts() {
        List<Account> acct = 
            [SELECT id
             FROM Account
             WHERE id = :ApexPages.currentPage().getParameters().get('id')];

        List<Contact> results =
            [SELECT Id, AccountId, Full_Name__c, Email, Phone, Title
             FROM Contact 
             WHERE (AccountId = :acct AND No_Longer_with_Company__c = False)];

        return results;
    }
}

The unit test inserts 50 new contacts, should I call to my getContacts method to get code coverage? Any pointers would be greatly appreciated.

Unit Test:

@isTest
class ContactsListControllerTest {
    static testMethod void testContactList (){
        //Insert 50 test contacts
        List<Contact> contacts = new List<Contact>();

        for (Integer count = 0; count < 50; count++) {
            contacts.add(new Contact (FirstName = 'John'+count, LastName ='Doe'+count));
        }

        insert contacts;

    }


}
5

It is a best practice to separate unit tests from functionality tests. If you run your method from trigger on contacts insert and you want to cover functionality, you can write some method like this

static testMethod void testContactList (){
    //Insert 50 test contacts
    List<Contact> contacts = new List<Contact>();

    for (Integer count = 0; count < 50; count++) {
        contacts.add(new Contact (FirstName = 'John'+count, LastName ='Doe'+count));
    }
    Test.startTest();
        insert contacts;
    Test.startTest();
    // add some asserts here!
}

If you are writing just a unit test for this method, you need to put it inside startTest-stopTest like this:

static testMethod void testContactList (){
    //Insert 50 test contacts
    List<Contact> contacts = new List<Contact>();

    for (Integer count = 0; count < 50; count++) {
        contacts.add(new Contact (FirstName = 'John'+count, LastName ='Doe'+count));
    }
    insert contacts;
    ContactsListController cc = new ContactsListController(new ApexPages.StandardController(new Account()));
    Test.startTest();
        cc.getContacts();
    Test.startTest();
    // add some asserts here!
}

Don't forget to add asserts, you always need asserts to make sure your code works as expected.


Let me add some more suggestions.

Inside your method, you don't have to make two SOQL queries, one would be enough.

SOQL query calls are very costly and there is a limit on its amount during transaction ( you can make no more than 200 calls ) so you have to eliminate unnecessary SOQL queries.

I mean you can refactor your method

public List<Contact> getContacts() {
    List<Account> acct = 
        [SELECT id
         FROM Account
         WHERE id = :ApexPages.currentPage().getParameters().get('id')];

    List<Contact> results =
        [SELECT Id, AccountId, Full_Name__c, Email, Phone, Title
         FROM Contact 
         WHERE (AccountId = :acct AND No_Longer_with_Company__c = False)];

    return results;
}

in a following way:

public List<Contact> getContacts() {
    return 
        [SELECT Id, AccountId, Full_Name__c, Email, Phone, Title
         FROM Contact 
         WHERE (AccountId = :acct.Id AND No_Longer_with_Company__c = False)];
}

It is a good idea to have a factory utility class having methods to create records like following:

/**
 * This is an utility class to contain helper methods to create test data.
 */
@isTest 
public class TestUtils {
/**
 * Helper method to create Account standard object records
 * 
 * @param Integer numToCreate: This parameter orders which amount of records should be created and inserted
 * 
 * @returns List<Account>: Created and inserted list of Account standard object records
 */
public static List<Account> createAccounts(Integer numToCreate) {
    List<Account> listToReturn = new List<Account>();
    for ( Integer i = 0; i < numToCreate; i++ ) {
        listToReturn.add( new Account( Name = 'Account ' + i ) );
    }
    insert listToReturn;
    return listToReturn;
}

/**
 * Helper method to create Contact standard object records
 * 
 * @param Account account: This parameter supplies a single master record to populate on all the children
 * @param Integer numToCreate: This parameter controls how many Contact standard object records should be created
 * @param Boolean doInsert: This parameter commands if created data should be inserted here
 * 
 * @returns static List<Contact>: Created and inserted list of Contact standard object records
 */
public static List<Contact> createContacts( Account account, Integer numToCreate, Boolean doInsert ) {
    List<Contact> listToReturn = new List<Contact>();
    for ( Integer i = 0; i < numToCreate; i++ ) {
        listToReturn.add(
            new Contact(
                FirstName = 'John' + i,
                LastName = 'Doe' + i,
                AccountId = account.Id
            )
        );
    }
    if (doInsert)
        insert listToReturn;
    return listToReturn;
}
}

Then you can organize your test method like follows

static testMethod void testContactList (){
    Account acc = TestUtils.createAccounts( 1 )[0];
    //Insert 50 test contacts
    List<Contact> contacts = TestUtils.createContacts( acc, 50, true );

    ContactsListController cc = new ContactsListController(new ApexPages.StandardController(a));
    Test.startTest();
        contacts = cc.getContacts();
    Test.startTest();
    System.assertEquals( 50, contacts.size(), 'Contact list size should match amount of created test records size' );
    // add some other asserts here!
}

Note that to make your test meaningful you have to attach contacts to account otherwise you won't receive any records returned.

Also it is good idea to have positive and negative use cases.

For example, you may create 50 records not attached to account ( negative cases ), 50 records attached to account but having No_Longer_with_Company__c set to true ( negative cases ) and 50 records attached to account having No_Longer_with_Company__c set to false ( positive cases ).

Only the last 50 record should be returned by your method in your test case.

  • Thanks so much for the suggestion. I really just need to get a unit test to verify the contacts being return. The controller is called from a VF page that just builds a contact list for a sidebar component in Service Cloud. – Allen Mann Dec 15 '15 at 13:50

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.