2

I'm trying to write test class for a visualforce extension. The extension is designed to use wrappers to add actions (Action__c) to a parent object Activity__c. The actions are child objects and the user can add as many as they like. They can also delete the actions.

My problem is that I do not understand how to write the test classes for these wrapper objects. When I try to delete a wrapper (e.deleteAction();) in my test class I get the following error:

System.NullPointerException: Attempt to de-reference a null object Stack Trace Class.ActionEditExt.getActionWrapperPos: line 87, column 1 Class.ActionEditExt.deleteAction: line 148, column 1 Class.ActionEditExtTest.ActionEditExtTest: line 65, column 1

Also, could you please tell me how can I set values for actions I add in my test class? i.e., after I call e.addAction(); in my test class, how can I set the values for the vf fields 'Description' and 'Date'?

Thank you in advance for any help/ suggestions :-)

Please see the following code for reference:

Visualforce page (part that's relevant)

<apex:page standardController="Activity__c" extensions="ActivityExtension,ActionEditExt" showHeader="true" sidebar="true" id="pg"> ....   
<table class="list" border="1" cellpadding="0" cellspacing="0" style="display: {!IF(actionWrappers.size=0, 'none', 'table')};">
        <tr class="headerRow">
          <th colspan="2" style="width:50%">Action Description</th>
          <th style="width:5%">Date</th>
          <th style="width:10%"></th>
        </tr>
        <apex:repeat value="{!actionWrappers}" var="actionWrap">
          <tr class="dataRow"> 
            <td colspan="2">
              <apex:inputField style="width:80%" value="{!actionWrap.ac.Description__c}" styleClass="masterClass commentBox2" />
            </td>
            <td  class="hideCurrDate">
              <apex:inputField value="{!actionWrap.ac.Date__c}"/>
            </td>
            <td >
              <apex:commandButton value="Delete" action="{!deleteAction}" rerender="tableOne">
                <apex:param name="actionToDel" value="AC{!actionWrap.key}" assignTo="{!actionToDel}"/>
              </apex:commandButton> 
            </td>
          </tr>
        </apex:repeat>
      </table>
      <apex:commandButton value="Add Action" action="{!addAction}" rerender="tableOne" immediate="true"/>

My Custom Controller

public List<ActionKeyWrapper> actionWrappers {get; set;}
public ApexPages.StandardController stdCtrl {get; set;}
private Integer key=1;  
public String actionToDel {get; set;}
private List<Action__c> actionsToDelete=new List<Action__c>();

public ActionEditExt(ApexPages.StandardController std)
  {
       stdCtrl=std;

       List<Action__c> actions=[select id, Description__c, Date__c
                      from Action__c
                      where Activity__r.Id=:stdCtrl.getId()];    

       actionWrappers=new list<ActionKeyWrapper>();

       for (Action__c ac : actions)
       {
           actionWrappers.add(new ActionKeyWrapper(key++, ac));
        }
}

private Integer getActionWrapperPos(String keyStr)
    {
        Integer key=Integer.valueOf(keyStr.substring(2));
        Integer result=-1;

        Integer index=0;
        for (ActionKeyWrapper cand : actionWrappers)
        {
            if (cand.key==key)
            {
                result=index;
                break;
            }
            else
            {
                index++;
            }
        }

        return result;
    }

private ActionKeyWrapper getActionWrapper(String keyStr)
    {
        ActionKeyWrapper wrapper=null;
        Integer pos=getActionWrapperPos(keyStr);
        if (-1!=pos)
        {
            wrapper=actionWrappers.get(pos);
        }        
        return wrapper;
    }

public PageReference deleteAction()
    {
        Integer pos=getActionWrapperPos(actionToDel);
        if (-1!=pos)    
        {
            ActionKeyWrapper wrapper=actionWrappers.get(pos);
            if (null!=wrapper.ac.Id)
            {
                actionsToDelete.add(wrapper.ac);
            }
            actionWrappers.remove(pos);
        }
        return null;
    }

public PageReference addAction()
    {
        actionWrappers.add(
                new ActionKeyWrapper(key++, 
                      new Action__c(Activity__c=stdCtrl.getId())));

        return null;
    }

public PageReference save()
    {
        List<Action__c> actions=new List<Action__c>();
        for (ActionKeyWrapper wrapper : actionWrappers)
        {
            actions.add(wrapper.ac);         
        }
            upsert actions;
            delete actionsToDelete;

        return stdCtrl.save();
    }
}

My Test Class

@isTest

private class ActionEditExtTest {

    public static testMethod void ActionEditExtTest(){

    //Activity
    Activity__c activity = new Activity__c();
    activity.Activity__c = '321';
    insert activity;

    //start the test execution context
    Test.startTest();

    PageReference pageRef = Page.ActivityEdit;
    Test.setCurrentPage(pageRef);
    ApexPages.currentPage().getParameters().put('std', activity.Id);
    ApexPages.StandardController sc = new ApexPages.StandardController(activity);
    ActionEditExt e = new ActionEditExt(sc);
    system.debug(pageRef);

    e.addAction();

    e.save();

    e.deleteAction();
    e.save();

    //stop the test
    Test.stopTest();

    }

}

1 Answer 1

2

The property actionToDel in your controller, you are not setting it in your test. Also I recommend having multiple tests for different methods, just to make sure that when a test fails you know where to look first.

If you want I can show you some examples in Apex.

UPDATE

Sorry for the late reply, but from what I see from the code actionToDel is a string although it should be the index of the actionWrappers list.

I believe you are on the right way to the test, you inserted an activity but you can't linked an action to that activity.

So after this code:

//Activity
Activity__c activity = new Activity__c();
activity.Activity__c = '321';
insert activity;

//Action
Action__c action = new Action__c();
action.Activity__c = activity.Id;
insert action;

//start the test execution context
Test.startTest();

PageReference pageRef = Page.ActivityEdit;
Test.setCurrentPage(pageRef);
ApexPages.currentPage().getParameters().put('std', activity.Id);
ApexPages.StandardController sc = new ApexPages.StandardController(activity);
ActionEditExt e = new ActionEditExt(sc);
system.debug(pageRef);
e.actionToDel = 'AC1';

e.addAction();
e.deleteAction();

Test.stopTest();

Then you can leave the rest of test as it is. Let me know if it gives you the same error. If it's giving you the required test cover that's ok but I recommend splitting them in multiple test methods. I will help you with that as well.

Hope it helps.

8
  • this is how I'm trying to set actionToDel in my test class: public String actionToDel = actionWrappers[0];, but I get the error " Illegal modifier on local variable". I don't get what the String value is for actionToDel, I thought it should be a position in the list of wrappers
    – rwegner7
    Commented Jan 24, 2015 at 16:03
  • Thank you @Mihai :-) Yes, I understand that I'm missing actionToDel in my test class (i.e. when I press Delete Action, it's looking for an actionToDel integer that isn't there.). I don't know how to assign actionToDel when I add the action, as well as how to assign other variables for action (i.e. Description__c) Can you please show me in Apex how to do this? Or point me to a link that does?
    – rwegner7
    Commented Jan 24, 2015 at 17:27
  • Your controller in the test is called e, so all you have to do is call e.actionToDel = "Your value here" , then call the delete method Commented Jan 24, 2015 at 18:11
  • Thank you @Mihai, I've tried that, but what do I replace "Your value here" with? I've tried inserting a number, (e.actionToDel = "1";) and get the error "no viable alternative at character". I've also tried setting it equal to actionWrappers.key(1), because that's the value I see in the vf page. Still doesn't work though...I guess I'm not understanding what actionToDel is, is it a number, a place in an array/ list, or is it text?
    – rwegner7
    Commented Jan 24, 2015 at 18:40
  • 1
    Thank you Mihai!!! That was it, just adding AC to the front! I got this extension code from an example in the VF cookbook, where they were adding both cases and case comments to an account, that's why they needed AC and CS in front of their {actionWrap.key} for Case and Case Comment, respectively, to differentiate the keys for each type of item being added. You're a real life saver Mihai, thank you again!
    – rwegner7
    Commented Jan 25, 2015 at 16:40

You must log in to answer this question.

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