Calling addFields in Extension class works on page, fails in test class

I’ve got a class which acts as a controller extension. The class is designed to add a number of fields to the StandardController so a component used on the page can dynamically access some fields.

However, when I went to test the class, I encountered the error:

System.SObjectException: You cannot call addFields when the data is being passed into the controller by the caller.

I tried using reset():

System.SObjectException: You cannot call reset when the data is being passed into the controller by the caller.

As far as I can tell, the data is fully initialized before it is passed along to the next object. I’m at a bit of a loss on how to cover these lines. The code below is an example that exhibits the same behavior, right now, the code I am using I just skip the line using Test.isRunningTest, but I’d like a solution to provide total coverage.

Extension Class

public class TestController_extension {  
    public TestController_extension(ApexPages.StandardController standardController) {
        standardController.addFields(new List<String>{});
    }
}

Test Class

@isTest
private class TestController_extension_test {
    @isTest
    private static void test() {
        Account a = new Account(); 
        ApexPages.StandardController controller = new ApexPages.StandardController(a);
        TestController_extension extension = new TestController_extension(controller); 
    }
}

Answer

Indeed you cannot call addFields from a test. This is one of the very few cases where you just have to check Test.isRunningTest.

You will get total coverage, however, if you one-line it. Declare your list separately, and then call addFields on the same line as your check:

public Account record { get; private set; }
public MyExtension(ApexPages.StandardController controller)
{
    List<String> fields = new List<String> { /*fields*/ };
    if (!Test.isRunningTest()) controller.addFields(fields); // still covered
    record = (Account)controller.getRecord();
}

Note that when you pass an SObject to a StandardController, it will still have all of its fields defined, so for the most part you don’t need to worry about query fields when testing.


There are a few alternatives which I do not typically use, but have seen around. You might prefer to just query for the data yourself:

public Account record { get; private set; }
public MyExtension(ApexPages.StandardController controller)
{
    record = [SELECT ... FROM Account WHERE Id = :controller.getId()];
}

And one final option which I find more distasteful, you can make sure the fields are included in your markup instead. Imo this approach mixes concerns in an ugly way, but it does work.

<apex:inputHidden value="{!record.FieldToQuery}" />

Attribution
Source : Link , Question Author : battery.cord , Answer Author : Adrian Larson

Leave a Comment