+ Start a Discussion
Chris PulliamChris Pulliam 

Code Coverage Help: Link in Email to Visualforce Confirmation Page

<apex:page id="Page" showHeader="false" controller="MyCustomVFPage_CTR" action="{!InitPage}" cache="false">
    <apex:form >
        Thank you for your response.
    </apex:form>
</apex:page>
^ Visualforce page. When someone clicks a link in an alert email I sent them it directs them here, and appends a value in the url based on what link in the alert they click: accepted or rejected. 
 
public class MyCustomVFPage_CTR {
    public String ObjectId {get;set;}
    public String ResponseCode {get;set;}
    public MyCustomVFPage_CTR () {
        ObjectId = ApexPages.currentPage().getParameters().get('ObjectId');
        ResponseCode = ApexPages.currentPage().getParameters().get('ResponseCode');
    }
    public PageReference InitPage() {
        List<Lead> CustomerIssues = [SELECT Id, Status FROM Lead WHERE Id=:ObjectId LIMIT 1];
        if(!CustomerIssues.IsEmpty()){
            CustomerIssues[0].Status = ResponseCode;
            UPDATE CustomerIssues;
        }
        Return null;
    }
}
^ class takes the value that's passed from the url, and updates the related record.

I don't know how to get code coverage for that class. Do I need to write something to test going to a visualforce page?





 
Best Answer chosen by Chris Pulliam
Amit Chaudhary 8Amit Chaudhary 8
Please check below post to learn about test classes
1) http://amitsalesforce.blogspot.com/search/label/Test%20Class
2) http://amitsalesforce.blogspot.com/2015/06/best-practice-for-test-classes-sample.html

Please try below test class.
@isTest 
public class MyCustomVFPage_CTRTest 
{
	static testMethod void testMethod1() 
	{

		Lead lead=new Lead(LastName='Doe',FirstName='John',Company='Test',Status='Converted');
		insert lead;  

		
		Test.StartTest(); 
		
			PageReference pageRef = Page.MyCustomVFPage; // Add your VF page Name here
			pageRef.getParameters().put('ResponseCode', 'Test');
			pageRef.getParameters().put('ObjectId', String.valueOf(lead.Id));
			Test.setCurrentPage(pageRef);
			
			MyCustomVFPage_CTR obj = new MyCustomVFPage_CTR();

			obj.InitPage(); 
			
		Test.StopTest();
	}
}

Please follow below salesforce Best Practice for Test Classes :-

1. Test class must start with @isTest annotation if class class version is more than 25
2. Test environment support @testVisible , @testSetUp as well
3. Unit test is to test particular piece of code working properly or not .
4. Unit test method takes no argument ,commit no data to database ,send no email ,flagged with testMethod keyword .
5. To deploy to production at-least 75% code coverage is required
6. System.debug statement are not counted as a part of apex code limit.
7. Test method and test classes are not counted as a part of code limit
9. We should not focus on the  percentage of code coverage ,we should make sure that every use case should covered including positive, negative,bulk and single record .
Single Action -To verify that the the single record produces the correct an expected result .
Bulk action -Any apex record trigger ,class or extension must be invoked for 1-200 records .
Positive behavior : Test every expected behavior occurs through every expected permutation , i,e user filled out every correctly data and not go past the limit .
Negative Testcase :-Not to add future date , Not to specify negative amount.
Restricted User :-Test whether a user with restricted access used in your code .
10. Test class should be annotated with @isTest .
11 . @isTest annotation with test method  is equivalent to testMethod keyword .
12. Test method should static and no void return type .
13. Test class and method default access is private ,no matter to add access specifier .
14. classes with @isTest annotation can't be a interface or enum .
15. Test method code can't be invoked by non test request .
16. Stating with salesforce API 28.0 test method can not reside inside non test classes .
17. @Testvisible annotation to make visible private methods inside test classes.
18. Test method can not be used to test web-service call out . Please use call out mock .
19. You can't  send email from test method.
20.User, profile, organization, AsyncApexjob, Corntrigger, RecordType, ApexClass, ApexComponent ,ApexPage we can access without (seeAllData=true) .
21. SeeAllData=true will not work for API 23 version eailer .
22. Accessing static resource test records in test class e,g List<Account> accList=Test.loadData(Account,SobjectType,'ResourceName').
23. Create TestFactory class with @isTest annotation to exclude from organization code size limit .
24. @testSetup to create test records once in a method  and use in every test method in the test class .
25. We can run unit test by using Salesforce Standard UI,Force.com IDE ,Console ,API.
26. Maximum number of test classes run per 24 hour of period is  not grater of 500 or 10 multiplication of test classes of your organization.
27. As apex runs in system mode so the permission and record sharing are not taken into account . So we need to use system.runAs to enforce record sharing .
28. System.runAs will not enforce user permission or field level permission .
29. Every test to runAs count against the total number of DML issued in the process .


Please let us know if this post will help you

Thanks,
Amit Chaudhary

All Answers

Amit Chaudhary 8Amit Chaudhary 8
Please check below post to learn about test classes
1) http://amitsalesforce.blogspot.com/search/label/Test%20Class
2) http://amitsalesforce.blogspot.com/2015/06/best-practice-for-test-classes-sample.html

Please try below test class.
@isTest 
public class MyCustomVFPage_CTRTest 
{
	static testMethod void testMethod1() 
	{

		Lead lead=new Lead(LastName='Doe',FirstName='John',Company='Test',Status='Converted');
		insert lead;  

		
		Test.StartTest(); 
		
			PageReference pageRef = Page.MyCustomVFPage; // Add your VF page Name here
			pageRef.getParameters().put('ResponseCode', 'Test');
			pageRef.getParameters().put('ObjectId', String.valueOf(lead.Id));
			Test.setCurrentPage(pageRef);
			
			MyCustomVFPage_CTR obj = new MyCustomVFPage_CTR();

			obj.InitPage(); 
			
		Test.StopTest();
	}
}

Please follow below salesforce Best Practice for Test Classes :-

1. Test class must start with @isTest annotation if class class version is more than 25
2. Test environment support @testVisible , @testSetUp as well
3. Unit test is to test particular piece of code working properly or not .
4. Unit test method takes no argument ,commit no data to database ,send no email ,flagged with testMethod keyword .
5. To deploy to production at-least 75% code coverage is required
6. System.debug statement are not counted as a part of apex code limit.
7. Test method and test classes are not counted as a part of code limit
9. We should not focus on the  percentage of code coverage ,we should make sure that every use case should covered including positive, negative,bulk and single record .
Single Action -To verify that the the single record produces the correct an expected result .
Bulk action -Any apex record trigger ,class or extension must be invoked for 1-200 records .
Positive behavior : Test every expected behavior occurs through every expected permutation , i,e user filled out every correctly data and not go past the limit .
Negative Testcase :-Not to add future date , Not to specify negative amount.
Restricted User :-Test whether a user with restricted access used in your code .
10. Test class should be annotated with @isTest .
11 . @isTest annotation with test method  is equivalent to testMethod keyword .
12. Test method should static and no void return type .
13. Test class and method default access is private ,no matter to add access specifier .
14. classes with @isTest annotation can't be a interface or enum .
15. Test method code can't be invoked by non test request .
16. Stating with salesforce API 28.0 test method can not reside inside non test classes .
17. @Testvisible annotation to make visible private methods inside test classes.
18. Test method can not be used to test web-service call out . Please use call out mock .
19. You can't  send email from test method.
20.User, profile, organization, AsyncApexjob, Corntrigger, RecordType, ApexClass, ApexComponent ,ApexPage we can access without (seeAllData=true) .
21. SeeAllData=true will not work for API 23 version eailer .
22. Accessing static resource test records in test class e,g List<Account> accList=Test.loadData(Account,SobjectType,'ResourceName').
23. Create TestFactory class with @isTest annotation to exclude from organization code size limit .
24. @testSetup to create test records once in a method  and use in every test method in the test class .
25. We can run unit test by using Salesforce Standard UI,Force.com IDE ,Console ,API.
26. Maximum number of test classes run per 24 hour of period is  not grater of 500 or 10 multiplication of test classes of your organization.
27. As apex runs in system mode so the permission and record sharing are not taken into account . So we need to use system.runAs to enforce record sharing .
28. System.runAs will not enforce user permission or field level permission .
29. Every test to runAs count against the total number of DML issued in the process .


Please let us know if this post will help you

Thanks,
Amit Chaudhary
This was selected as the best answer
Chris PulliamChris Pulliam
Amit, thank you! Code Coverage100% (11/11)
Abhi MalikAbhi Malik
@Amit Chaudhary Sir
Please help me to write test class for this trigger

********************trigger*****************

trigger WorkerStatusBefore on schnja__Worker_Status__c (before delete, before insert, before update) {
    
    if(Trigger.isInsert){
            TriggersWorkerStatus.handleBeforeInsert(Trigger.new);
    }
    else if(Trigger.isUpdate){
        TriggersWorkerStatus.handleBeforeUpdate(Trigger.oldMap,Trigger.newMap);
    }
    else if(trigger.isDelete){
        UtilWorkerStatus.checkAccessList(trigger.old);
    }  
}


********************UtilWorkerStatusClass*****************************
public with sharing class UtilWorkerStatus {
    
    public static Worker_Status__c createWorkerStatus(Id workerId, DateTime startDateTime, DateTime endDateTime, Id recordType){
        Worker_Status__c newWorkerStatus = generateWorkerStatus(workerId, startDateTime, endDateTime, recordType);
        insert newWorkerStatus;
        return newWorkerStatus;
    }
    public static Worker_Status__c generateWorkerStatus(Id workerId, DateTime startDateTime, DateTime endDateTime, Id recordType){
        return new Worker_Status__c(
            Worker__c = workerId, 
            Start_Date_Time__c = startDateTime, 
            End_Date_Time__c = endDateTime,
            RecordTypeId = recordType);
    }
    
    public static Worker_Status__c createDummyWorkerStatus(Id workerId, Id orgId){
        Worker_Status__c newWorkerStatus = generateDummyWorkerStatus(workerId, orgId);
        insert newWorkerStatus;
        return newWorkerStatus;
    }
    
    public static Worker_Status__c generateDummyWorkerStatus(Id workerId, Id orgId){
        if(orgId == null){
            orgId = UtilOrgLevel.createOrgLevel('Dummy', null).Id;
        }
        if(workerId == null){
            workerId = UtilWorker.createWorker('Dummy', 'Worker', orgId).Id;
        }
        return generateWorkerStatus(workerId, DateTime.now().addHours(1), DateTime.now().addHours(6), UtilGeneral.getRecordTypeId('schnja__Worker_Status__c', 'One-Time Availability'));
    }
    
    public static Map<Id,Boolean> checkAccessList (List<Worker_Status__c> record){
        Map <Id, boolean> accessMap = new Map <Id, boolean> ();
        //Check to see if the current user is an Availability Admin, If so return true for all Ids
        if(UtilGeneral.avilabilityPermissions.Availability_Admin__c){
            //Iterate through records, add them to accessMap with True and return it
            for(Worker_Status__c accessRecord:record){
                accessMap.put(accessRecord.Id,True);
            }
            return accessMap;
        }
        //Build a list of Ids of the scheduled Workerss
        system.debug(record);
        List <Id> workerIDs = new List <Id> ();
        for (Worker_Status__c accessRecord:record){
            workerIDs.add(accessRecord.Worker__c);
        }

        // Query to get the contact record of the scheduled workers
        Map <Id, Worker__c> currentWorker = new Map <Id,Worker__c> ([select Id, User_Record__c, Reports_To__r.User_Record__c from Worker__c where Id in :workerIds]);
        Id currentUser = UserInfo.getUserId();
        Boolean managersCanEdit = UtilGeneral.defaultSettings.Managers_Can_Edit_Availability__c;

        // Iterate through records, check to see if the user has access to change that record.  Add the Id and true to accessMap if they have access, false if not
        for (Worker_Status__c accessRecord:record){ 
            if(currentUser == currentWorker.get(accessRecord.Worker__c).User_Record__c || managersCanEdit && currentWorker.get(accessRecord.Worker__c).Reports_To__r.User_Record__c == currentUser){
                accessMap.put(accessRecord.Id,True);
            }else{
                accessMap.put(accessRecord.Id,False);
            }
        }
        return accessMap;
    }
    public static List<Worker_Status__c> generateNewInstances(Worker_Status__c recurring)
    {
        List<Worker_Status__c> newInstances = new List<Worker_Status__c>{};
        // Set the beginning Instance date to the start date of the 
        //  recurring or budget transaction
        DateTime currentStart = recurring.schnja__Start_Date_Time__c;
        DateTime currentEnd = recurring.schnja__End_Date_Time__c;
        
        // Determine the end date for the instance transactions
        // TODO:  Update this to look at the organization's Availability Settings
        Date finalDate = recurring.schnja__Repeat_Until__c == null ? (Date) recurring.schnja__Start_Date_Time__c.addYears(2) : recurring.schnja__Repeat_Until__c; 
        
        Id instanceRecordTypeId = UtilGeneral.getRecordTypeId('schnja__Worker_Status__c', 'Availability Instance');
        
        while(currentStart<=finalDate)
        {
            Worker_Status__c newStatus = UtilWorkerStatus.generateWorkerStatus(recurring.schnja__Worker__c, currentStart, currentEnd, instanceRecordTypeId);
            newStatus.Instance_Of__c = recurring.Id;
            newStatus.Description__c = recurring.Description__c;
            
            newInstances.add(newStatus);
            
            if(recurring.schnja__Recurrence_Interval__c == 'Days')
            {
                currentStart = currentStart.addDays(recurring.schnja__Recurs_Every__c.intValue());
                currentEnd = currentEnd.addDays(recurring.schnja__Recurs_Every__c.intValue());
            }
            else if(recurring.schnja__Recurrence_Interval__c == 'Weeks')
            {
                currentStart = currentStart.addDays(recurring.schnja__Recurs_Every__c.intValue() * 7);
                currentEnd = currentEnd.addDays(recurring.schnja__Recurs_Every__c.intValue() * 7);
            }
            else if(recurring.schnja__Recurrence_Interval__c == 'Months'){
                currentStart = currentStart.addMonths(recurring.schnja__Recurs_Every__c.intValue());
                currentEnd = currentEnd.addMonths(recurring.schnja__Recurs_Every__c.intValue());
            }
            else{
                currentStart = currentStart.addYears(recurring.schnja__Recurs_Every__c.intValue());
                currentEnd = currentEnd.addYears(recurring.schnja__Recurs_Every__c.intValue());
            }
        }
        
        return newInstances;
    }


********************TriggersWorkerStatusClass***********************


public class TriggersWorkerStatus {
    public static void handleAfterInsert(Map<Id, Worker_Status__c> triggerMap){
        //Get list of recurring Worker Statuses
        //system.debug(Schema.getGlobalDescribe().get('schnja__Worker_Status__c').getDescribe().getRecordtypeInfosByName());
        
        list <Worker_Status__c> recurringStatus = new list <Worker_Status__c>();
        Id recurringStatusID = UtilGeneral.getRecordTypeId('schnja__Worker_Status__c', 'Recurring Availability');
        for (Worker_Status__c newStatus: triggerMap.values()){
            if (newStatus.RecordTypeID == recurringStatusID) recurringStatus.add(newStatus);
        }
        //If the list isn't empty, iterate through list and pass them to generateNewInstances
        if (!recurringStatus.isEmpty()){
            list <Worker_Status__c> newInstances = new list <Worker_Status__c>();
            for(Worker_Status__c newRecurringStatus: recurringStatus){
                newInstances.addAll(UtilWorkerStatus.generateNewInstances(newRecurringStatus));
            }
            //Insert list of new Instance records if it is not empty
            if (!newInstances.isEmpty()) insert newInstances;
        }
    }
    public static void handleAfterUpdate(Map<Id, Worker_Status__c> beforeMap, Map<Id, Worker_Status__c> afterMap){
        //create blank list of Worker Statuses
        list <Id> busyStatus = new list <Id>();
        //iterate through list of updated records
        for (Worker_Status__c updatedRecord: afterMap.values()){
            //check to see if the status is canceled.
            if(updatedRecord.Status__c == 'Canceled'){
                //If the status is cancelled, check to see if the dates or times have changed
                if (updatedRecord.Start_Date_Time__c != beforeMap.get(updatedRecord.ID).Start_Date_Time__c || updatedRecord.End_Date_Time__c != beforeMap.get(updatedRecord.ID).End_Date_Time__c){
                    //If they have set the Worker Status to Busy and add them to the list of Worker statuses to update
                    busyStatus.add(updatedRecord.Id);
                }
            }    
        }
        
        //Update the changed statuses if the list isn't empty (and everything that goes with it)
        if (!busyStatus.isEmpty()){
            list <Worker_Status__c> updatedStatus = [SELECT Id, Status__c from Worker_Status__c where Id in :busyStatus];
            for (Worker_Status__c statusRecord : updatedStatus){
                statusRecord.Status__c = 'Busy';
            }
            update updatedStatus;
        }
    }
    public static void handleBeforeUpdate(Map<Id, Worker_Status__c> beforeMap, Map<Id, Worker_Status__c> afterMap){
        //Check access and attach errors to records that the user doesn't have permission to modify
        Map <Id,Boolean> accessMap = UtilWorkerStatus.checkAccessList(afterMap.Values());
        for(Worker_Status__c statusRecord:afterMap.Values()){
            if(!accessMap.get(statusRecord.Id)) statusRecord.addError('You have insufficient rights to update this Worker Status record.');
        }
    }
    public static void handleBeforeInsert(List <Worker_Status__c> beforeList){
        //Check access and attach errors to records that the user doesn't have permission to modify
        // system.debug(beforeList);
        Map <Id,Boolean> accessMap = UtilWorkerStatus.checkAccessList(beforeList);
        for(Worker_Status__c statusRecord:beforeList){
            if(!accessMap.get(statusRecord.Id)) statusRecord.addError('You have insufficient rights to update this Worker Status record.');
        }
    }
    
    public static void handleBeforeDelete(List <Worker_Status__c> AfterList){
        //Check access and attach errors to records that the user doesn't have permission to Delete
        Map <Id,Boolean> deletemap = UtilWorkerStatus.checkAccessList(AfterList);
        for(Worker_Status__c statusRecord:AfterList){
            if(!deletemap.get(statusRecord.Id)) statusRecord.addError('You have insufficient rights to Delete this Worker Status record.');
        }
    }
}
 
Arthur LawrenceArthur Lawrence
Hi Amit and Chris, thank you for your post.
Question:How to show respective page based on the conditions as stated below.
public class MyCustomVFPage_CTR {
    public String ObjectId {get;set;}
    public String ResponseCode {get;set;}
    public MyCustomVFPage_CTR () {
        ObjectId = ApexPages.currentPage().getParameters().get('ObjectId');
        ResponseCode = ApexPages.currentPage().getParameters().get('ResponseCode');
    }
    public PageReference InitPage() {
        List<Lead> CustomerIssues = [SELECT Id, Status, Campaign FROM Lead WHERE Id=:ObjectId AND Campaign ='Current' LIMIT 1];
        if(!CustomerIssues.IsEmpty()){
            CustomerIssues[0].Status = ResponseCode;
            UPDATE CustomerIssues;
show "Thank you page"
        }
        Return "Campaign is not current page";
    }
}
Appreciate your help!
Thanks
Arthur