2

My Visualforce page is calling Controller methods using apex:actionFunction and are not being executed while I am implementing the test class. Also in my test class I have test contact records which are not being fetched by the SOSL query from the Controller causing other methods to not executed.

Main controller(partial):

public Contact cont {get;set;}
public List<Contact> relatedConsList {get;set;}
//Constructor 
 public ParentController(ApexPages.StandardController stdController){
    List<String> contactFields = new List<String>{'Name', 'Email'}; 
        if (!Test.isRunningTest()) stdController.addFields(contactFields); 
    this.cont=(Contact)stdController.getRecord();
        Contact currentCont = [Select Id, FirstName, LastName, Email FROM Contact WHERE Id =: cont.Id];
        relatedConsList = ParentControllerHelper.searchRelatedContacts(currentCont.FirstName, currentCont.LastName, currentCont.Id, currentCont.Email);
 }
 public List<contactWrapper> processConts(){
    if(contactList == null){
        contactList = new List<contactWrapper>();
        if(relatedConsList.size() > 0){
            System.debug('Related List not Empty: ' +relatedConsList);
            for(Contact c: relatedConsList){
                contactList.add(new contactWrapper(c));
            } 
        }
    }
    return contactList;
 }

Helper class(partial):

Public static List<Contact> searchRelatedContacts(String firstName, String lastName, String contId, String email){
    String searchTerm = '';

    if(firstName != null){
        if(lastName != null){
            searchTerm += '('+firstName+' AND '+lastName+')' ;
        } else {
            searchTerm += firstName;
        }
    } else {
        if(lastName != null) {
            searchTerm += lastName;
        }
    }
    List<Contact> relatedConsList = new List<Contact>();
    relatedConsList = [FIND :searchTerm 
                       IN ALL FIELDS
                       RETURNING Contact(
                           Name,Id,Email,Phone,MobilePhone
                           WHERE Email <> NULL AND Id <> :contId)][0]; 
    System.debug('After query: ' +relatedConsList); //Getting as Empty in test execution all the time
    return relatedConsList; 
}

Test class:

@testSetup static void setup() {

    List<Account> testAccts = new List<Account>();
    for(Integer i=0;i<2;i++) {
        testAccts.add(new Account(Name = 'TestAcct'+i));
    }
    insert testAccts;

    List<Contact> testConts = new List<Contact>();
    for (Integer i=0;i<10;i++){
        testConts.add(new Contact(FirstName = 'Test', MiddleName= 'M'+i,  LastName = 'lName', Email = '[email protected]'+i, AccountId=testAccts[0].Id));
    }

    testConts[4].AccountId = testAccts[1].Id; //Changing AccountId 
    testConts[5].AccountId = testAccts[1].Id; 
    testConts[6].AccountId = testAccts[1].Id; 
    testConts[7].AccountId = testAccts[1].Id; 

    insert testConts;
    System.debug('Testsetup: ' +testConts[0].Id);
    System.debug('Inserted Test Cons: ' +testConts);
}

@isTest
static void testMethodForCons(){

    Contact con = [Select Id, FirstName, LastName, Email FROM Contact LIMIT 1];
    List<Contact> testConsList = [SELECT Id, FirstName, LastName, Email 
                                  FROM Contact WHERE FirstName =: con.FirstName]; //I can query the test records. 
    Test.startTest();
        PageReference pr = Page.myVFPage;
        Test.setCurrentPageReference(pr);
        ApexPages.currentPage().getParameters().put( 'Id', con.Id );
        ApexPages.Standardcontroller sc = new ApexPages.Standardcontroller(con);
        ParentController ctrl = new ParentController(sc);
        Id [] fixedSearchResults= new Id[1];
        fixedSearchResults[0] = con.Id;
        Test.setFixedSearchResults(fixedSearchResults);
        //The above statements doesn't help with the Controller's SOSL execution

        ctrl.processConts(); //Not executing as SOSL not getting the test contacts list. 
    Test.stopTest();

}

3 Answers 3

3

Adding SOSL Queries to Unit Tests

To ensure that test methods always behave in a predictable way, any Salesforce Object Search Language (SOSL) query that is added to an Apex test method returns an empty set of search results when the test method executes. If you do not want the query to return an empty list of results, you can use the Test.setFixedSearchResults system method to define a list of record IDs that are returned by the search. All SOSL queries that take place later in the test method return the list of record IDs that were specified by the Test.setFixedSearchResults method. Additionally, the test method can call Test.setFixedSearchResults multiple times to define different result sets for different SOSL queries. If you do not call the Test.setFixedSearchResults method in a test method, or if you call this method without specifying a list of record IDs, any SOSL queries that take place later in the test method return an empty list of results.

The list of record IDs specified by the Test.setFixedSearchResults method replaces the results that would normally be returned by the SOSL query if it were not subject to any WHERE or LIMIT clauses. If these clauses exist in the SOSL query, they are applied to the list of fixed search results. For example:

@isTest
private class SoslFixedResultsTest1 {

    public static testMethod void testSoslFixedResults() {
       Id [] fixedSearchResults= new Id[1];
       fixedSearchResults[0] = '001x0000003G89h';
       Test.setFixedSearchResults(fixedSearchResults);
       List<List<SObject>> searchList = [FIND 'test' 
                                         IN ALL FIELDS RETURNING 
                                            Account(id, name WHERE name = 'test' LIMIT 1)];
    }
}
6
  • I came across this documention already. And also I can see the Test execution to run over my controller's SOSL query, but, still the variable: relatedConsList is getting empty. Can you please take a look at my code? Commented Apr 5, 2018 at 18:21
  • The code you included does not call this method.
    – Adrian Larson
    Commented Apr 5, 2018 at 18:22
  • Method searchRelatedContacts from my helper class. I am calling this in the Constructor of my Parent controller. Commented Apr 5, 2018 at 18:24
  • No Test.setFixedSearchResults. You don't call it in your unit test. That's what you need to fix.
    – Adrian Larson
    Commented Apr 5, 2018 at 18:26
  • Nope, including this doesn't made any difference. Still the variable: relatedConsList is empty. Commented Apr 5, 2018 at 18:31
2

You need to call Test.setFixedSearchResults, which basically accepts a list of records to find:

Test.setFixedSearchResults(new Id[] { testConts[0].Id });

Alter this code to include all the ID values you want to return.

2
  • I am seeing the test execution to pass over the SOSL query. But I am not sure whether it is querying the test data. Commented Apr 5, 2018 at 18:24
  • When my Controller class's constructor is being executed at unit test, will the SOSL query gets executed? If yes, will it fetch the test contact records that are created as a part of testSetup? Commented Apr 5, 2018 at 20:01
2

Here's your problem:

The call to Test.setFixedSearchResults(fixedSearchResults); is occurring after the constructor for the controller executes - and the constructor is the code fragment that does the SOSL

Test.startTest();
    PageReference pr = Page.myVFPage;
    Test.setCurrentPageReference(pr);
    ApexPages.currentPage().getParameters().put( 'Id', con.Id );
    ApexPages.Standardcontroller sc = new ApexPages.Standardcontroller(con);
    ParentController ctrl = new ParentController(sc);
    Id [] fixedSearchResults= new Id[1];
    fixedSearchResults[0] = con.Id;
    Test.setFixedSearchResults(fixedSearchResults); // too late!

do:

Test.startTest();
        PageReference pr = Page.myVFPage;
        Test.setCurrentPageReference(pr);
        ApexPages.currentPage().getParameters().put( 'Id', con.Id );
        ApexPages.Standardcontroller sc = new ApexPages.Standardcontroller(con);
        Id [] fixedSearchResults= new Id[1];
        fixedSearchResults[0] = con.Id;
        Test.setFixedSearchResults(fixedSearchResults); // before constructor
        ParentController ctrl = new ParentController(sc);
6
  • I am still not getting any data even after changing to above. Am I still missing anything? Or the test data from testSetup won't be considered as data for querying(from controller) while executing test class? Commented Apr 6, 2018 at 14:21
  • it could be because your SOSL call is excluding the value of contId which is the same contact as the one you set in setFixedSearchResults - perhaps setFixedSearchResults should return a contact other than con.Id
    – cropredy
    Commented Apr 6, 2018 at 15:30
  • I am getting this error: Method does not exist or incorrect signature: void setFixedSearchResults(List<Contact>) from the type System.Test when I try: Contact [] fixedSearchResults= new Contact[1]; fixedSearchResults[0] = con; Test.setFixedSearchResults(fixedSearchResults);. can you help me fix this? Commented Apr 6, 2018 at 16:17
  • @AustinEvans - you have to supply list<ID>, not List<sobject>. See sfdcfox answer
    – cropredy
    Commented Apr 6, 2018 at 19:38
  • I am still unable to fetch the data(Even after successful SOSL execution) after following your's and sfdcfox's ans. Commented Apr 9, 2018 at 15:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .