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
Chris MoynihanChris Moynihan 

Test Case Help

I am trying to write a test case for my page/controller. I've written test code for triggers before without a lot of trouble, but it's been a long time and I am having trouble getting my tests written. Below is my code, as well as where I am with my test code so far.

The page/controller let's me add multiple entries for a custom object so I can enter a bunch at once and then save them.

Any help and direction is much appreciated.

Controller:
public class MultiAddSEActivities
{
    
    // Holds the SE Activity records to be saved
    public List<SE_Activities__c>recList  = new List<SE_Activities__c>();
    
    // List of the recClass
    public List<recClass> actRecords
    {get;set;}
    
    // Indicates the row to be deleted
    public String selectedRowIndex
    {get;set;}  
    
    // # of records in the recClass list
    public Integer count = 0;
    
    // Save the records by adding the elements in the record class list to recList, return to the same page
    public PageReference Save()
    {
        PageReference pr = new PageReference('/a00/o');
        
        for(Integer j = 0;j<actRecords.size();j++)
        {
            recList.add(actRecords[j].seact);
        } 
        insert recList;
        pr.setRedirect(True);
        return pr;
    }
        
    // Add a row
    public void Add()
    {   
        count = count+1;
 
        // Call to the recClass constructor
        recClass objRecClass = new recClass(count);
        
        // Add the record to the recClass list
        actRecords.add(objRecClass);
    }
    
    // Add duplicate of last row
    public void dupe()
    {
        if (count == 0){
            return;
        }else{
            
            // Create new Record Class record
            recClass dupeRecord = new recClass(count+1);
            
            // Get duplicate record from temp list
            dupeRecord.seact = actRecords[count-1].seact.clone(false,true,false,false);
            
            // Add the record to the record class list
            actRecords.add(dupeRecord);
            
            count = count + 1;
        }
    }
    
    // Delete row
    public void Del()
    {
        
        // Find the matching record in the list and remove it
        Integer j = 0;
        while (j < actRecords.size())
        {
          if(actRecords.get(j).recCount == selectedRowIndex)
          {
            actRecords.remove(j);
            count = count - 1;
          }
          else
          {
            j++;
          }
        }

        // Reset recCount for each record in the list
        Integer r = 0;
        while (r < actRecords.size())
        {
           actRecords[r].recCount = String.valueOf(r+1);
           r++;
        }     
    }
    
    
    // Constructor
    public MultiAddSEActivities()
    {
        //ApexPages.StandardController ctlr
        actRecords = new List<recClass>();
        Add();
        selectedRowIndex = '0';   
    }


    // Record Class
    public class recClass
    {       
        // recCount acts as a index for a row. This will be helpful to identify the row to be deleted
        public String recCount
        {get;set;}

        public SE_Activities__c seact 
        {get;set;}

        // Record Class Constructor
        public recClass(Integer intCount)
        {
            // Set the index
            recCount = String.valueOf(intCount);     
            
            // Create a new SE Activity
            seact = new SE_Activities__c();
            
        }
    }
}

Test Code:
@isTest
public class controllerTests {

    public static testMethod void testMultiAddSEActivitiesPage(){
    
        PageReference pg = Page.MultiAddSEActivities;
        Test.setCurrentPage(pg);
        
        MultiAddSEActivities controller = new MultiAddSEActivities();
        String nextPage = controller.Save().getUrl();

        // Instantiate a new controller with all params on the page
        controller = new MultiAddSEActivities();
        controller.Add();
        controller.dupe();
        controller.Del();
        
        public List<SE_Activities__c> testList  = new List<SE_Activities__c>();
        
        // ?????
        
        nextPage = controller.Save().getUrl();

    }
}

Page:
<apex:page controller="MultiAddSEActivities" id="thePage">
<apex:form >
<apex:pageblock id="pb" >
    <apex:pageBlockButtons >
        <apex:commandbutton value="Add" action="{!Add}" rerender="pb1"/>
        <apex:commandbutton value="Duplicate Last" action="{!Dupe}" rerender="pb1"/>
        <apex:commandbutton value="Save" action="{!Save}"/>
    </apex:pageBlockButtons>
    
    <apex:pageblock id="pb1">
            
        <apex:repeat value="{!actRecords}" var="e1" id="therepeat">
             <apex:panelGrid columns="8">
                
                <apex:panelGrid headerClass="Name" width="15px">
                    <apex:facet name="header">Delete</apex:facet>
                    <apex:commandButton value="x" action="{!Del}" rerender="pb1">
                        <apex:param name="rowToBeDeleted" value="{!e1.recCount}" assignTo="{!selectedRowIndex}"></apex:param>
                    </apex:commandButton>
                </apex:panelGrid>   

                <apex:panelGrid title="SPD">
                    <apex:facet name="header">Activity Date</apex:facet>
                    <apex:inputfield value="{!e1.seact.Activity_Date__c}"/>
                </apex:panelGrid>
                
                <apex:panelGrid >
                    <apex:facet name="header">Opportunity</apex:facet>
                    <apex:inputfield style="width:250px" value="{!e1.seact.OpportunityLink__c}"/>
                </apex:panelGrid>
                
                <apex:panelGrid >
                    <apex:facet name="header">Type</apex:facet>
                    <apex:inputfield value="{!e1.seact.Type__c}"/>
                </apex:panelGrid>
                
                <apex:panelGrid >
                    <apex:facet name="header">Hours</apex:facet>
                    <apex:inputfield style="width:30px" value="{!e1.seact.Hours__c}"/>
                </apex:panelGrid>
                                
                <apex:panelGrid >
                    <apex:facet name="header">Comments</apex:facet>
                    <apex:inputfield style="width:250px; height:12px" value="{!e1.seact.Comments__c}"/>
                </apex:panelGrid>
                
                <apex:panelGrid >
                    <apex:facet name="header">Onsite</apex:facet>
                    <apex:inputfield value="{!e1.seact.Onsite__c}"/>
                </apex:panelGrid>
                
            </apex:panelgrid>
        </apex:repeat>
        
    </apex:pageBlock>        
</apex:pageblock>
</apex:form>
</apex:page>


 
Best Answer chosen by Chris Moynihan
David ZhuDavid Zhu
Actually, I think your test case has cover most line of the code. 
I modified your test case by adding assertions in the test case to make it complete.
 
@isTest
public class controllerTests {

    public static testMethod void testMultiAddSEActivitiesPage(){
    
       
        MultiAddSEActivities controller = new MultiAddSEActivities();

        controller.dupe();
	system.assertequals(controller.count,0);

        controller.Add();
	system.assertequals(controller.count,1);

        controller.dupe();
	system.assertequals(controller.count,2);

	controller.selectedrowindex = 2;
        controller.Del();
	system.assertequals(controller.count,1);
        
    String nextPage = controller.Save().getUrl();
	system.assert(nextPage.Contains(@'/a00/o');

    }
}

 

All Answers

David ZhuDavid Zhu
Actually, I think your test case has cover most line of the code. 
I modified your test case by adding assertions in the test case to make it complete.
 
@isTest
public class controllerTests {

    public static testMethod void testMultiAddSEActivitiesPage(){
    
       
        MultiAddSEActivities controller = new MultiAddSEActivities();

        controller.dupe();
	system.assertequals(controller.count,0);

        controller.Add();
	system.assertequals(controller.count,1);

        controller.dupe();
	system.assertequals(controller.count,2);

	controller.selectedrowindex = 2;
        controller.Del();
	system.assertequals(controller.count,1);
        
    String nextPage = controller.Save().getUrl();
	system.assert(nextPage.Contains(@'/a00/o');

    }
}

 
This was selected as the best answer
Chris MoynihanChris Moynihan
Thanks David.

I had to modify that ever so slightly (remove the @ symbol and move the check to a variable, fix the count values, change the selected row index to a string value) but then it worked with 97% coverage. Below is my final code.
@isTest
public class controllerTests {

    public static testMethod void testMultiAddSEActivitiesPage(){
        
        MultiAddSEActivities controller = new MultiAddSEActivities();
        
        controller.Add();
        system.assertequals(controller.count,2);
        
        controller.dupe();
        system.assertequals(controller.count,3);

        controller.selectedrowindex = '3';
        
        controller.Del();
        system.assertequals(controller.count,2);
        
        String nextPage = controller.Save().getUrl();
        Boolean check = nextPage.Contains('/a00/o');
        system.assert(check);
    }
}

 
Chris MoynihanChris Moynihan
One other question though...

If I set up a trigger to do validation on the SE_Activities__c object to make sure a date field has a date in it, my validation rule is triggered with this test method and it fails.

Do I have to create a test activity with a date here and how do I keep the test on the Save call from failing?
David ZhuDavid Zhu
I would suggest you add the code like this in your (BEFORE) triger.
 
foreach( SE_Activities__c sa : trigger.new)
{
     if (sa.Activity_Date__c == null)
         sa.Activity_Date__c.addError('Date Cannot be empty');
.....
}



In test case:
 
SE_Activities__c sa = new SE_Activities__c();
sa.name = 'xxx';
sa.otherfields = 'xxxxxxxxxx';
//sa.Activity_Date__c  dont assign value to this field
    try
        {
            insert sa;
        }
        catch(Exception e)
        {
            System.assert(e.getMessage().contains('Date Cannot be empty'));   //match the error text in addError 
        }
    ...

 
Chris MoynihanChris Moynihan
Thanks. I already had something very similar that works testing the trigger on it's own.

The problem is that with the trigger, the controllerTests method fails, since upon calling the Save() test line, there is no date.

Error Message:
System.DmlException: Insert failed. First exception on row 0; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, Please add an Activity Date.: [Activity_Date__c]
Stack Trace:
Class.MultiAddSEActivities.Save: line 27, column 1
Class.MultiAddSEActivitiesPageTest.MultiAddSEActivitiesPageTest: line 19, column 1
Which refers to this line in the test method
String nextPage = controller.Save().getUrl();
and the insert recList; in the page code:
public PageReference Save()
    {
        PageReference pr = new PageReference('/a00/o');
        
        for(Integer j = 0;j<actRecords.size();j++)
        {
            recList.add(actRecords[j].seact);
        } 
        insert recList;
        pr.setRedirect(True);
        return pr;
    }
I'm not sure how to get the test of the Save method to have dates in it.



 
David ZhuDavid Zhu
Because you did not assign a value to Activity_Date__c,  Insert RecList will always fail.

You can either add a default value through recClass constructor by adding:

seact.Activity_Date__c = today();

or in ADD() , add:
objeRecClass.seact.Activity_Date__c = today();

and in DUPE(), add:
dupeRecord.seact.Activity_Date__c = today();

Basically, you need to assign value to Activity_Date__c for each record.
Chris MoynihanChris Moynihan
I don't want to modify the real code, because users should be entering dates.

I just need to add a date for the test code so it doesn't trigger that error. However, since I'm not actually creating a record with the test code, I don't see how I can do that.

I am guessing I need to create a record with data in it and somehow use that to test the Save() method, but I can't seem to figure out how to do that and assign it to the controller in the test.
David ZhuDavid Zhu
I guess I understand what you want.
 
@isTest
public class controllerTests {

    public static testMethod void testMultiAddSEActivitiesPage(){
        
        MultiAddSEActivities controller = new MultiAddSEActivities();
        
        controller.Add();
        system.assertequals(controller.count,2);
        
        controller.dupe();
        system.assertequals(controller.count,3);

        controller.selectedrowindex = '3';
        
        controller.Del();
        system.assertequals(controller.count,2);
        
        for(recCalss rc : controller.actRecords)
        { 
            rc.seact.activity_date__c = today();
        }

        String nextPage = controller.Save().getUrl();
        Boolean check = nextPage.Contains('/a00/o');
        system.assert(check);
    }
}




 
Chris MoynihanChris Moynihan
Yes! Thank you.

That was the missing link for me.