About

Edit photo

Thursday, February 16, 2017

APEX Test Classes - Examples



Apply @istest annotation to code.

Signature Characterisitics:

  • static --- test method must be a static
  • void  --- it should always no return type.
  • no parameters --- Don't use parameters.

Example:
@istest
public class myclass
{
     @istest private static void mytest() {...}
     //or
     private static void testmethod mytest() {...}
}


Test cannot do:

  • commit changes to DB.
  • Perform callouts to external systems.
  • send outbound messages.

SOQL cannot find pre-existing data, except

  • user
  • profile
  • organization
  • record type
But if use @istest(seealldata=true) annotation, can get data from all the objects.


Test Requirements:

  • Atleast 75% apext statement must be executed.
  • All apex triggers must be called
  • All apex tests must executed without any exceptions / exceeding governors. 

we use,

  • system.assert()
  • system.assertequals()
  • system.assertnotequals()
Note: i) pass upto 200 records only. ii) Don't depend on pre-existing data.

Imp: use Test.StartTest() and Test.StopTest()

Example:
I have 3 objects named, a, b, c. C is parent of B and A,  B is parent of A. A to B has Master, B to C has Master, A to C has lookup. I want to get the C name to my A where B's object is having C.

trigger afrombfromc on a__c (before insert, before update) {
 set<id> aID = new set<id>();
 set<id> bID = new set<id>();
 set<id> cID = new set<id>();
 
 for(a__c a1:trigger.new)
 {
  bID.add(a1.b_object__c);
 }
 
    map<id,b__c> map2;
    map<id,c__c> map3;
    
 if(!bID.isempty())
  map2 = new map<id,b__c>([select id, name, b_field__c, c_object__c from b__c where id in:bID]);
    
    for(b__c b:map2.values())
    {
        cID.add(b.c_object__c);
    }
    
    if(!cID.isempty())
  map3 = new map<id,c__c>([select id, c_field__c from c__c where id in:cID ]);
 
 for(a__c a1:trigger.new)
 {
  a1.b_field__c = map2.get(a1.b_object__c).b_field__c;
  //a1.c__c = map3.get(map2.get(a1.b_object__c).b_object__c).id;
  a1.c__c = map3.get(map2.get(a1.b_object__c).c_object__c).id;
 }/span>
}

Apex Test Class:

@istest public class afrombfromc_test {
 @istest public static void mytest1()
    {
        c__c c = new c__c();
        c.name = 'cname';
        insert c;
        b__c b = new b__c();
        b.name = 'bname';
        b.c_object__c = c.id;
        insert b;
        a__C a = new a__c();
        a.name = 'aname';
        a.b_object__c = b.id;
        insert a;
        a__c asoql = [select c__c from a__c where id=:a.id];
        system.assertEquals(asoql.c__c, c.id);
    }
}




Thursday, February 9, 2017

Approval process using apex


An approval process is an automated process which can be used to approve/reject record updates. A record can be submitted for approval request from related list "Approval History". Once a records is submitted it goes for approval to a specified approver. This is a manual process where in every record should be individually sent for approval.
 How about doing this using apex? Sending the record fro approval from trigger? Salesforec provides number of method for handling approval processes in apex.

Let us submit a record for approval process from trigger in an example below.

Lets say you have a approval process named "Account Owner Approval". You can create a approval process by navigating to following:
set up --> create --> approval process





















Trigger to submit a account record for approval if its annual revenue is less then 2000
?
1
2
3
4
5
6
7
8
9
10
trigger Call_AprovalProcess_In_Trigger on Account (before insert, before update) {
 for(Account acc:trigger.new){
    if(acc.AnnualRevenue < 2000){
       approval.ProcessSubmitRequest aprlPrcs = new Approval.ProcessSubmitRequest();     
       aprlPrcs .setComments('Submitting record for approval.');
       aprlPrcs.setObjectId(acc.id);
       approval.ProcessResult result = Approval.process(aprlPrcs);
    }
 }
}

send email in apex salesforce


Salesforce provides method to send emails from apex. We can create a instance of that method, set all the required parameters and then send the emails.

We can set the email addresses to which the email be sent in "setToAddresses", we can give emails seperated by comma. Simialrly bcc,cc email addresses can be seperated by comma . We can specify the body as text or HTMl as desired.

Following is a example wherein emails will be sent to specified addresses upon clicking the button.

Visualforce page <apex:page controller="SendemailController">
 <apex:form >
   <apex:commandButton value="Send Email" action="{!sendEmailFunction}"/>
 </apex:form>
</apex:page>


Controller 
Public with sharing class SendemailController{
   Public SendemailController(){
   }
  
 Public void sendEmailFunction(){
   Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
   String[] toAddresses = new String[] {'testreceipient1@mail.com','testreceipient1@mail.com'}; 
   String[] ccAddresses = new String[] {'testcc1@mail.com','testcc1@mail.com'};
   mail.setToAddresses(toAddresses);
   mail.setCcAddresses(ccAddresses);
   mail.setReplyTo('myemail@mail.com');
   mail.setSenderDisplayName('My Name');
   mail.setSubject('Testing email through apex');
   mail.setBccSender(false);
   mail.setUseSignature(false);
   mail.setPlainTextBody('This is test email body. This mail is being sent from apex code');
   //mail.setHtmlBody('<b> This is HTML body </b>' );
   Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
 } 

}

You need to specify the existing correct addresses in the lines marked red in abive code.

avoid recursive trigger salesforce


Recursion occurs when the code gets called again and again and goes into a infinite loop. It is always advisable to write a code that does not call itself. However, sometimes we are left with no choice. Recursion occurs in trigger if your trigger has a same DMLstatement and the same dml condition is used in trigger firing condition on the same object(on which trigger has been written)
For example, if your trigger fires on after update on contact and you update any contact record in your trigger then the same trigger will be called and will lead to a infinite loop.
To avoid this kind of recursion and call the trigger only once we can use global class static variable.
As an example let says you have following trigger on contact:
trigger recursiveTrigger on Contact (after update) {
Id recordId ;
 for(contact con : trigger.new){
     recordId = con.id;
 }
 Contact conRec =[select id,name,email from contact where id !=: recordId limit 1];

 conRec.email = 'testemail@kmail.com';
 update conRec;
 }
}
As you can see the trigger is getting called on after update and as the trigger has a DML update statement on the same object, same trigger will be called again leading to recursion.
To avoid this, just create one global class with a static global boolean variable as below.
global Class recusrssionPreventController{
Global static boolean flag = true;
 Public recusrssionPreventController(){
 }
}
And set this boolean variable in your trigger and then set this boolean variable to false as done in the trigger below
trigger recursiveTrigger on Contact (after update) {
Id recordId ;
if(recusrssivePreventController.flag == true){
   recusrssivePreventController.flag = false;
 for(contact con : trigger.new){
     recordId = con.id;
 }
 Contact conRec =[select id,name,email from contact where id !=: recordId limit 1];

 conRec.email = 'testemail@kmail.com';
 update conRec;
 }
}
This will call the trigger only once and hence avoid recursion.

LEAD conversion in trigger


trigger ConvertLeadtrigger on Lead (after insert,after update) {
   Integer Count =0;
    Database.LeadConvert[] leadCollectionArray = new Database.LeadConvert[trigger.new.size()] ;
    for(Lead Lea : trigger.new){
        if(Lea.rating == 'Hot'){
          Database.LeadConvert convLead = new database.LeadConvert();
          convLead .setLeadId(Lea.Id);
          convLead.setConvertedStatus('Closed - Converted');
          convLead .setDoNotCreateOpportunity(true);
          leadCollectionArray[count] = convLead ;
          count++;
         }
    }   
    Database.LeadConvertResult[] LeaConvResults = Database.convertLead(leadCollectionArray,false);
}

If you need to create manually and need to update more fields, go for this example.

SOSL Example in Salesforce




system.debug([FIND 'test' IN ALL FIELDS RETURNING  Account (Id,Name,type),Contact(name,email),Opportunity(name,StageName),Lead(company,name,status)]);

Dynamic: The following program search the field com* in account, opportunity and contacts and gets the output in visualforce page.


Apex Class:

public class SOSL {
    public list<account> acclist {set;get;}
    public list<opportunity> opplist {get;set;}
    public list<contact> conlist {get;set;}
    
    public SOSL()
    {
        acclist = new list<account>();
        opplist = new list<opportunity>();
        conlist = new list<contact>();
    }
    
    public void soslMtd()
    {
        list<list<sobject>> searchlist = [find 'com*' in ALL FIELDS RETURNING ACCOUNT (id,name,type),contact(name,email),opportunity(name,stagename)];
        acclist = (list<account>)searchlist[0];
        conlist = (list<contact>)searchlist[1];
        opplist = (list<opportunity>)searchlist[2];
    }
    
    
}

Visualforce Page:
<apex:page controller="SOSL">
    <apex:form>
     <apex:commandButton value="Show records using SOSL" action="{!soslMtd}"/>
        <apex:pageBlock title="accounts">
         <apex:pageBlockTable value="{!acclist}" var="a">
             <apex:column value="{!a.name}"/>
                <apex:column value="{!a.id}"/>
            </apex:pageBlockTable>
        </apex:pageBlock>
        <apex:pageBlock title="contacts">
         <apex:pageBlockTable value="{!conlist}" var="c">
             <apex:column value="{!c.name}"/>
                <apex:column value="{!c.email}"/>
            </apex:pageBlockTable>
        </apex:pageBlock>
        <apex:pageBlock title="opportunity">
         <apex:pageBlockTable value="{!opplist}" var="p">
             <apex:column value="{!p.name}"/>
                <apex:column value="{!p.stagename}"/>
            </apex:pageBlockTable>
        </apex:pageBlock>
    </apex:form>
</apex:page>

Output: