function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Damien_Damien_ 

test controller.addFields method

My controller works correctly, but when I go to test it I get an error and I'm not sure how to fix it.  Can anybody help?

 

static testMethod void testInquiryToProject()
  {
      List<Case> inquiries = [SELECT ID FROM Case LIMIT 1];
    
    if (inquiries.size() > 0)
    {
        Case inquiry = inquiries[0];
      ApexPages.StandardController controller = new ApexPages.StandardController(inquiry);
      controller.reset();
      InquiryToProjectExtension ext = new InquiryToProjectExtension(controller);
    }else
      System.debug('No Cases available');
  }

 

////////////////////////////////////////////////////////////////////////////////////

 

ublic InquiryToProjectExtension(ApexPages.StandardController cont)
  {
    List<String> fields = new List<String>();
    fields.add('Account');
    fields.add('CaseNumber');
    fields.add('Neighborhood_Lookup__c');
    fields.add('Sector__c');
    fields.add('Owner');
    fields.add('In_a_Main_Street_District__c');
    fields.add('Main_Street_Districts__c');
    cont.addFields(fields);//I get my error here when my test method executes
    inquiry = (Case)cont.getRecord();
    project = new Project__c(RecordType = [select id, name from RecordType where Name =: 'Grant'], Project_Account__c = inquiry.accountID, Neighborhood_Lookup__c = inquiry.Neighborhood_Lookup__c, Sector__c = inquiry.Sector__c, Project_Manager__c = UserInfo.getUserId(), In_a_Main_Street_District__c = inquiry.In_a_Main_Street_District__c, Main_Street_District__c = inquiry.Main_Street_Districts__c);
    controller = new ApexPages.StandardController(project);
  }

Ritesh AswaneyRitesh Aswaney

Maybe you could try calling reset on the controller just before invoking the addFields Method?

 

so

cont.reset()

cont.addFields(....

Damien_Damien_

I had already tried that and it failed.  I ended up writing a SOQL query to get the fields I needed, but its obviously not the best way to do it.

bob_buzzardbob_buzzard

Can you post the error message?

kevoharakevohara

I am also getting the same error.  Does anyone have a fix for this?

 

Here is the debug log:

 

Debug Log:

 

20.0 APEX_CODE,DEBUG;APEX_PROFILING,INFO;CALLOUT,INFO;DB,INFO;VALIDATION,INFO;WORKFLOW,INFO

15:38:12.230|EXECUTION_STARTED

15:38:12.230|CODE_UNIT_STARTED|[EXTERNAL]|01pM0000000Cf3A|TestRestrictionsViewOnLeadControllerExt.myUnitTest

15:38:12.230|METHOD_ENTRY|[23]|01pM0000000Cf3A|TestRestrictionsViewOnLeadControllerExt.TestRestrictionsViewOnLeadControllerExt()

15:38:12.230|METHOD_EXIT|[23]|TestRestrictionsViewOnLeadControllerExt

15:38:12.231|DML_BEGIN|[30]|Op:Insert|Type:Lead|Rows:1

15:38:12.291|CODE_UNIT_STARTED|[EXTERNAL]|Validation:Lead:new

15:38:12.291|VALIDATION_RULE|03dM00000008PVl|Require_opt_out_reason

15:38:12.292|VALIDATION_FORMULA|AND(OR(DoNotCall = true, HasOptedOutOfEmail = true), ISBLANK( TEXT(Opt_Out_Reason__c )))|DoNotCall=0 , Opt_Out_Reason__c=null , HasOptedOutOfEmail=0

15:38:12.292|VALIDATION_PASS

15:38:12.292|CODE_UNIT_FINISHED|Validation:Lead:new

15:38:12.381|CODE_UNIT_STARTED|[EXTERNAL]|Workflow:Lead

15:38:12.411|WF_RULE_EVAL_BEGIN|Assignment

15:38:12.411|WF_SPOOL_ACTION_BEGIN|Assignment

15:38:12.411|WF_ACTION|.

15:38:12.411|WF_RULE_EVAL_BEGIN|Response

15:38:12.411|WF_RULE_EVAL_BEGIN|Workflow

15:38:12.412|WF_RULE_EVAL_BEGIN|Escalation

15:38:12.412|WF_RULE_EVAL_END

15:38:12.412|WF_ACTIONS_END| None

15:38:12.412|CODE_UNIT_FINISHED|Workflow:Lead

15:38:12.412|DML_END|[30]

15:38:12.412|METHOD_ENTRY|[1]|Test.Test()

15:38:12.412|METHOD_EXIT|[1]|Test

15:38:12.412|METHOD_ENTRY|[33]|system.Test.setCurrentPage(Object)

15:38:12.413|METHOD_EXIT|[33]|system.Test.setCurrentPage(Object)

15:38:12.413|METHOD_ENTRY|[1]|01pM0000000CdMK|RestrictionsViewOnLeadControllerExt.RestrictionsViewOnLeadControllerExt()

15:38:12.414|METHOD_EXIT|[1]|RestrictionsViewOnLeadControllerExt

15:38:12.415|CONSTRUCTOR_ENTRY|[36]|01pM0000000CdMK|<init>(ApexPages.StandardController)

15:38:12.415|METHOD_ENTRY|[16]|LIST.add(ANY)

15:38:12.415|METHOD_EXIT|[16]|LIST.add(ANY)

15:38:12.415|METHOD_ENTRY|[17]|LIST.add(ANY)

15:38:12.415|METHOD_EXIT|[17]|LIST.add(ANY)

15:38:12.415|METHOD_ENTRY|[18]|LIST.add(ANY)

15:38:12.415|METHOD_EXIT|[18]|LIST.add(ANY)

15:38:12.416|METHOD_ENTRY|[19]|ApexPages.StandardController.addFields(LIST<String>)

15:38:12.416|EXCEPTION_THROWN|[19]|System.SObjectException: You cannot call addFields after you've already loaded the data.  This must be the first thing in your constructor

15:38:12.416|METHOD_EXIT|[19]|ApexPages.StandardController.addFields(LIST<String>)

15:38:12.416|CONSTRUCTOR_EXIT|[36]|<init>(ApexPages.StandardController)

15:38:12.416|FATAL_ERROR|System.SObjectException: You cannot call addFields after you've already loaded the data.  This must be the first thing in your constructor

 

Class.RestrictionsViewOnLeadControllerExt.<init>: line 19, column 9

Class.TestRestrictionsViewOnLeadControllerExt.myUnitTest: line 36, column 51

External entry point

15:38:12.881|CUMULATIVE_LIMIT_USAGE

15:38:12.881|LIMIT_USAGE_FOR_NS|(default)|

  Number of SOQL queries: 0 out of 100

  Number of query rows: 0 out of 50000

  Number of SOSL queries: 0 out of 20

  Number of DML statements: 1 out of 150

  Number of DML rows: 1 out of 10000

  Number of script statements: 16 out of 200000

  Maximum heap size: 0 out of 3000000

  Number of callouts: 0 out of 10

  Number of Email Invocations: 0 out of 10

  Number of fields describes: 0 out of 100

  Number of record type describes: 0 out of 100

  Number of child relationships describes: 0 out of 100

  Number of picklist describes: 0 out of 100

  Number of future calls: 0 out of 10

 

15:38:12.881|CUMULATIVE_LIMIT_USAGE_END

 

15:38:12.416|CODE_UNIT_FINISHED|TestRestrictionsViewOnLeadControllerExt.myUnitTest

15:38:12.416|EXECUTION_FINISHED

bob_buzzardbob_buzzard

Does your code match that of the OP?

bob_buzzardbob_buzzard

I've been playing with this for a while and it looks like a bug.  The fields get populated correctly when run outside of a test, but when the controller is constructed in a test method this error occurs regardless of where the addFields method is called.

 

That said, you shouldn't need to change your controller to use SOQL, you just need to ensure the test data is set up with those fields populated and also ensure that you don't attempt to execute the add fields when you are inside a test.

Ralph CallawayRalph Callaway

Ditto, this makes the feature unusable.  Yikes.  

 

Just logged a case.  Will update thread with response.

DevNVDevNV

Any word on this issue?  I just bumped up against it as well.

 

Cheers,  Niki

Damien_Damien_

Not really, I just put an <apex:variable> or something similar that doesn't show up on the page but it still makes the controller add the field in.  I just don't use the addFields at all.

bob_buzzardbob_buzzard

I wrote a small blog post a while ago with a workaround for this:

 

http://bobbuzzard.blogspot.com/2011/04/dynamic-visualforce-bindings-and.html

JayNicJayNic

Unfortunately Bob, this time your solution didn't work for me...

I'm adding in child relationships and they aren't getting picked up...

 

my controller adds:

stdCtrlr.addFields(
                new list<string>{
                    'name',
                    'RecordTypeName__c',
                    'OppNumber__c',
                    'AccountId',
                    'CurrencyIsoCode',
                    'Amount',
                    'OwnerId',
                    'IsClosed',
                    'stageName',
                    'Contracts__r',
                    'OpportunityPartnersFrom',
                    'OpportunityPartnersFrom.AccountToId',
                    'OpportunityPartnersFrom.Role',
                    'OpportunityPartnersFrom.isPrimary',
                    'ChildOpportunities__r'
                }
            );

 And of course it works at runtime - but I can't get those fields into my test method...

 

Just another reason why I think test methods are a waste of time and money... Make them consistent, Force!!!

Ralph CallawayRalph Callaway

JayNic, just don't use AddFields, I've logged a case for this a month ago and Salesforce doesn't seem to have this as a priority to fix.  Personally, I think it's pretty egregious that when Salesforce requires 75% test coverage of all classes that they could even release a function that ALWAYS fails in a test method. 

 

For now you can:

A) reference the fields or child relationships in your visualforce page and the standard controller will load them for you

B) query the fields yourself in your extension constructor

bob_buzzardbob_buzzard

@JayNic - is it any or all of the fields that you can't get into the test method?  

JayNicJayNic
Well it will get through all the fields on the record itself - but once i get to Contracts__r or any child - it would fail to find the info. When I loaded this data through the VF page it worked - but once again - it could not get that data into the test class. It seems the only reason to use the standard controller at all it to gain access to its validation rules...
Ralph CallawayRalph Callaway

@jaynic

 

before you instantiate your standard controller in your test method are you querying your test records child relationships?

 

e.g.

@isTest
private static void myTest() {
// create test data
Account testAccount = new Account(name = 'test');]
insert testAccount;
Contact contact = new Contact(lastName = 'test', accountId = testAccount.id);
insert contact;

// requery all fields you require in your extension before 
// instantiating the controller
testAccount = [select name, (select lastName from Contacts) from Account where id = :testAccount.id];
ApexPages.StandardController controller = new APexPages.StandardController(testAccount);
MyExtension extension = new MyExtension(controller);
}

If you want to save yourself a database call you could also do it this way:

@isTest
private static void myTest() {
// create test data
Account testAccount = new Account(name = 'test');
insert testAccount;
Contact testContact = new Contact(lastName = 'test', accountId = testAccount.id);
insert testContact;
testAccount.contacts = new Contact[] { testContact; }

// load extension
ApexPages.StandardController controller = new ApexPages.StandardController(testAccount);
MyExtension extension = new MyExtension(controller);

}

 The important things are:

1) Don't ever call addFields if a test is running (IMHO, just don't use it at all)

2) Have everything you need in your extension loaded into your account (or other sObject) before using it to instantiate the standard controller.  The standard controller when run in test methods, does NOT requery anything, but just takes whatever input you give it and runs with it.

JayNicJayNic

when ive tried to assign objects as children in the past ive always gotten a "field is not writable error..."

 

i can try again - for now i had to deploy for the client so i switchd to good ol reliable queiries

Ralph CallawayRalph Callaway

@JayNic, you're totally right, you can't assign child lists to an sobject, only parents.  Just wishful thinking.

Rahul SharmaRahul Sharma

In my case i just had neglected the addField call when called from test class. and it worked well.

Here it is:

public MyConstructor(ApexPages.StandardController stdCtrl) {
	if(!Test.isRunningTest()) {
		stdCtrl.addFields(new List<String> {'Name', 'Field1__c'});
	}
}

 Just thought to share this with others facing this error.

sunny.sfdcsunny.sfdc
Salesforce says you cannot use addfields() method when the data is passed by caller to the controller. So in a test method if you are passing a record to controller, it will throw error on addFields() method.

You need to put a check to skip this code while running tests. As Rahul suggested adding
if(!Test.isRunningTest())
HTH
Sachin