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
Tim__mTim__m 

Extension unit test and the standard controller outfields method

Hey everyone,

Hope someone can provide input on a unit test issue I'm running into. I have an extension on a custom object that works just fine when you view the VF page but I can't get my unit test to play nice. The error that is thrown when running the unit test is a SObject Exception: You cannot call addFields after you've already loaded the data. The call to addFields is the first thing in my constructor after I set a local property to the constructor arg, see the code snippets...

 

The Extension

public class MyExtension {
    public ApexPages.StandardController stdCtrl { get; set; }

    public MyExtension(ApexPages.StandardController controller) {
        stdCtrl = controller;
        stdCtrl.addFields(new String[] {'field1','field2'});
        ...
    }
}

The Unit Test 

@isTest
private class MyExtensionUnitTest {
    static testMethod void positive_UnitTest() {
        Test.startTest();
        Test.setCurrentPage(Page.MyPage); //a page that uses MyExtension
        system.runAs(testuser) {
            MyCustObj obj = [SELECT foo FROM MyCustObj WHERE id = :theId];
            MyExtension ext = new MyExtension(new ApexPages.StandardController(obj));
            //SObject exception thrown at this point

            //I try this too but same exception.

            MyExtension ext = new MyExtension(new ApexPages.StandardController(new MyCustObj()));
            //SObject exception thrown at this point
           
        }
    }
}

 

I understand the exception that is thrown but I don't know how to test an extension that uses the addFields method of the standard controller. 


Best Answer chosen by Admin (Salesforce Developers) 
Shashikant SharmaShashikant Sharma

Update your constructor like

 

public class MyExtension {
    public ApexPages.StandardController stdCtrl { get; set; }

    public MyExtension(ApexPages.StandardController controller) {
        stdCtrl = controller;
        if(!Test.isRunningTest())
            {
               stdCtrl.addFields(new String[] {'field1','field2'});
             }
        ...
    }
}

 And add all the fields in test method in standardcontroller instance instead of depending on the constructor code

 

@isTest
private class MyExtensionUnitTest {
    static testMethod void positive_UnitTest() {
        Test.startTest();
        Test.setCurrentPage(Page.MyPage); //a page that uses MyExtension
        system.runAs(testuser) {
            MyCustObj obj = [SELECT foo , field1 , field2 FROM MyCustObj WHERE id = :theId];
            MyExtension ext = new MyExtension(new ApexPages.StandardController(obj));
            //SObject exception thrown at this point

            //I try this too but same exception.

            
           
        }
    }
}

 Should work for you

All Answers

Shashikant SharmaShashikant Sharma

Update your constructor like

 

public class MyExtension {
    public ApexPages.StandardController stdCtrl { get; set; }

    public MyExtension(ApexPages.StandardController controller) {
        stdCtrl = controller;
        if(!Test.isRunningTest())
            {
               stdCtrl.addFields(new String[] {'field1','field2'});
             }
        ...
    }
}

 And add all the fields in test method in standardcontroller instance instead of depending on the constructor code

 

@isTest
private class MyExtensionUnitTest {
    static testMethod void positive_UnitTest() {
        Test.startTest();
        Test.setCurrentPage(Page.MyPage); //a page that uses MyExtension
        system.runAs(testuser) {
            MyCustObj obj = [SELECT foo , field1 , field2 FROM MyCustObj WHERE id = :theId];
            MyExtension ext = new MyExtension(new ApexPages.StandardController(obj));
            //SObject exception thrown at this point

            //I try this too but same exception.

            
           
        }
    }
}

 Should work for you

This was selected as the best answer
SteveBowerSteveBower

Does using:

 

stdCntrl.reset();

 

before the addFields() clear up the problem?   I agree that since you're in your Constructor it seems you shouldn't have to... but I wonder if it work.

 

 

From the vf doc...

 

Two Apex methods are used for dynamic Visualforce pages using standard controllers: addFields() and reset(). The addFields() method adds a list of field names to the StandardController indicating that they should be loaded; the reset() method refreshes the StandardController to prepare to retrieve these new references. For more information on these methods, see the StandardController documentation

Tim__mTim__m

reset() doesn't work. Tried that before posting, thought that should work but no luck.

 

Sharma's solution should do it and might be the only option, even thought its not right. I just don't like the idea of changes the path of code execution when running in test mode, defeats the purpose.

 

I should be able to pass an instance of an sobject in the same state that Salesforce dose it. That just gave me an idea, brb...

 

SteveBowerSteveBower

I agree wrt changing execution paths just for testing (unless it's structural), but this doesn't seem like it should require that.   Curious what you find.  Best, Steve.

Tim__mTim__m

Still no luck. So for now the workaround is to use isRunningTest(). When my bandwidth opens up I'm going to revisit this and post an update. Maybe I can find someone at dream force to show me the light.