Monday, 16 May 2022

Salesforce Apex Test classes

 

                                            TEST CLASSES

1.    What is test class in Salesforce?

Ans: When we are moving code from sandbox to production org we need to write a test class. Whatever apex class(code) we have written we need to ensure that each and every condition is correct. The code must have 75% coverage to deploy it to production, else we will not be able to deploy our code.

To create test class, we create test data in test classes, to check our functionality. We avoid using data from salesforce orgs.

 2.    What is code coverage and what is the minimum code coverage for class and trigger?

Ans : Code Coverage is the percentage number of lines covered by the test class by a total number of lines need to be covered.

Minimum code coverage for the trigger is at least 1% and for class, the overall code coverage of production should be above 75% before a new component can be deployed to the production.

 3.    Is it possible to write test code inside of an apex class or apex trigger?

Ans: We cannot write test code (test methods) inside of the apex trigger.

we cannot write the test methods inside of an apex class which is not decorated with @isTest. We can write test methods only in a class which is decorated with @isTest.

 We have a governor limit for the overall Apex Code size of the organization which is of 3 MB. If we decorate a class with @isTest annotation Apex Code Size governor limit will be bypassed.

 So basically, whatever we write inside @isTest annotation, will not be counted in apex code size governor limit.

 4.   Syntax of Test Method:

 @isTest

    private class MyTestClass {

  

       static testMethod void myTest1() {

       }

  

      static testMethod void myTest2() {

      }

  }

 5.    What is @testSetup annotation? When you will use it?

Ans: we all know that for most unit tests we need some test data, so to create test records once and then access them in every method, you have to use @TestSetup annotation in a test class. Data generated in @TestSetup will be persisted for use in every test method within the test class. Those data are created using @TestSetup annotation will roll back after the execution of the whole test class is complete.

Key points of @TestSetup annotation

Some key points of a @testsetup method are:

  1. Test setup method is time-saving.
  2. Reduce test execution time while working with many records.
  3. Multiple @testsetup methods are allowed in a test class.
  4. When an error is generated in the setup method then the entire test class fails.
  5. If the test class is marked with @isTest(SeeAllData=true), setup method can’t be used.
  6. Setup method won’t store a value in static variables.
  7. It won’t take arguments and don’t return value.

Syntax:

@testSetup static void testData() {

 }

Example:

6. What is a seeAllData=true?

Ans: Test classes run in a different context, i.e. a test class have no idea about the data stored in Salesforce, by setting seeAllData=true => @isTest(seeAllData = true).

if you mention @isTest(seeAllData = true) then test class can recognize the existing data in the database.

We should avoid using seeAllData = True.

7.What is @testVisible Annotation? When to use it?

Ans: Sometimes in test classes, we need to access a variable from apex classes, if it is private, we cannot Access for that we will replace Private with Public. For this reason, we will be compromising the security. To avoid this, Before the private variables in apex class, we can include @TestVisible so that even though variable is private, we can access in test classes.

Apex class:



Test class:

 


 8.     What are assert statements?

Ans: To compare Actual value and Expected value we use assert statements.

 Types of assert statements

A.     system.assertEquals(val1,val2): If both val1 and val2 are same then test class run successfully otherwise test class will fail.

B.     system.assertNotEquals(val1,val2): If both val1 and val2 are not same then test class run successfully otherwise test class will fail.

C.     system.assertEquals(val1> val2): If the condition satisfied then test class run successfully otherwise test class will fail.

  9.What is difference between System.Assert and System.AssertEquals ?

Ans: System.Assert accepts two parameters, one (mandatory) which is the condition to test for and the other a message (optional) to display should that condition be false.

System.AssertEquals and System.AssertNotEquals both accepts three parameters; the first two (mandatory) are the variables that will be tested for in/equality and the third (optional) is the message to display if the assert results in false.

Both are used in Test Class for “Positive Case Testing” and “Negative Case Testing” with single and multiple records.

10.What is the purpose of system.runAs()?

Ans: In general, apex code runs in System Mode, in system mode record sharing and permissions of the current user are not taken into account. The System.runAs() method enables a developer to write test methods that can change the user context to a new user created in the test or an existing user, this enforces records sharing for the specific user.

It also provides a way to handle mixed DML in test classes.

Points to consider while using system.Runas() :

·       You can only use the System.runAs method in test methods.

·       When the runAs method is complete, the original system context is started again.

·       System.runAs only enforces record sharing, it does not enforce field-level permissions or user permissions.

·       You can bypass mixed DML operations in your test class by having the DML operations inside the System.runAs block of code.

 

11. What is the purpose of Test.startTest() and Test.stopTest()?

Ans : To execute asynchronous methods synchronously we call these methods from inside of Test.startTest() and Test.stopTest(). Test.startTest() and Test.stopTest() maintains fresh set of governor limits. Assume that you are consuming 99 SOQL queries outside of Test.startTest() and Test.stopTest() then if you include any SOQL inside of Test.startTest() and Test.stopTest() count will start from 1.

Per testMethod we can use Test.startTest() and Test.stopTest() only for one time.

12. What do you mean by “Testing already started system exception”. When do we get this error?

Ans: This type of error occurs, when you write more than one Test.startTest & Test.stopTest() in a test class method. Per testMethod we can use Test.startTest() and Test.stopTest() only for one time.

13. What is the purpose of Test.isRunningTest()?

Ans : The Test.isRunningTest() method is used to identify, if the piece of code being executed is invoked from a Test class execution or from other artefacts such as a Trigger, Batch Job etc. Returns true if the currently executing code was called by code contained in a test method, false otherwise. Use this method if you need to run different code depending on whether it was being called from a test.

14. What is @isTest(OnInstall=true) ?

Ans : Use the @isTest(OnInstall=true) annotation to specify which Apex tests are executed during package installation. This annotation is used for tests in managed or unmanaged packages. Only test methods with this annotation, or methods that are part of a test class that has this annotation, are executed during package installation. Tests annotated to run during package installation must pass in order for the package installation to succeed. It is no longer possible to bypass a failing test during package installation. A test method or a class that doesn't have this annotation, or that is annotated with @isTest(OnInstall=false) or @isTest, is not executed during installation.

15.What is @isTest(isParallel=true)?

Ans: Use the @isTest(isParallel=true) annotation to indicate test classes that can run in parallel. Default limits on the number of concurrent tests do not apply to these test classes. This annotation makes the execution of test classes more efficient, because more tests can be run in parallel.

Considerations for the @isTest(isParallel=true) Annotation:

A.     This annotation overrides settings that disable parallel testing.

B.     @isTest(SeeAllData=true) and @isTest(isParallel=true) annotations cannot be used together on the same Apex method.


16.What is Test.setMock? When you will use it?

Ans : By default, test methods don’t support web service callouts, and tests that perform web service callouts fail.

To prevent tests from failing and to increase code coverage, Apex provides the built-in WebServiceMock interface and the Test.setMock method. Use WebServiceMock and Test.setMock to receive fake responses in a test method. So, Mainly we use this when we need to write test class for API callout or any other integration.

17. How to Write a test class for REST and SOAP?

Ans : The first step is to create a mock class for API callout. The first step is to create a class that implements the HTTPCalloutMock interface. The Mock class is nothing but a class that will generate a fake response for our API callout in the Test class. As, we don’t Need to hit the actual API, while testing we should have a fake response that will be returned when a callout is Performed.

The Mock class is also a test class with @isTest annotation that implements HTTPcalloutMock interface. This interface consists of single method respond() which accepts an instance of HTTPrequest class as a Parameter and return an instance of HTTPresponse which we will construct inside the Methods itself.

18. What is test Suite?

Ans : A test suite is a collection of Apex test classes that you run together.

 

Note :  For Best Practices of test class , https://learnsfdcwithmg.blogspot.com/2022/05/best-practices-of-apex-trigger-and-apex.html

 

 

Saturday, 14 May 2022

Triggers

 Triggers

Apex can be invoked by using triggers. Apex triggers enable you to perform custom actions before or after changes to Salesforce records, such as insertions, updates, or deletions. Use triggers to perform tasks that can’t be done by exploitation of the point-and-click tools within the Salesforce computer program.

Types of Apex Triggers:

1.      Before Trigger: - Before trigger can be used to update or validate values of a record before they are saved to database.

2.      After Trigger: - It can be used to access field values of the records that are stored in the database and use these values to make changes in other records.

Syntax:

trigger TriggerName on ObjectName (trigger_events) {

                 //    code_block

                     }

where trigger_events can be a comma-separated list of one or more of the following events:

1.   Before insert

2.   Before Update

3.   Before Delete

4.   After insert

5.   After Update

6.   After Delete

7.   After Undelete

 Trigger Context Variable :

 

Variables

Uses

Is Executing

Returns true if the current context for the Apex code is a trigger, not a Visualforce page, a Web service, or an execute anonymous() API call.

isInsert

Returns true if this trigger was fired due to an insert operation, from the Salesforce user interface, Apex, or the API.

isUpdate

Returns true if this trigger was fired due to an update operation, from the Salesforce user interface, Apex, or the API.

isDelete

Returns true if this trigger was fired due to a delete operation, from the Salesforce user interface, Apex, or the API.

isBefore

Returns true if this trigger was fired before any record was saved.

isAfter

Returns true if this trigger was fired after all records were saved.

isUndelete

Returns true if this trigger was fired after a record is recovered from the Recycle Bin. This recovery can occur after an undelete operation from the Salesforce user interface, Apex, or the API.

new

Returns a list of the new versions of the sObject records.
This sObject list is only available in 
insertupdate, and undelete triggers, and the records can only be modified in before triggers.

newMap

A map of IDs to the new versions of the sObject records.
This map is only available in 
before updateafter insertafter update, and after undelete triggers.

old

Returns a list of the old versions of the sObject records.
This sObject list is only available in 
update and delete triggers.

oldMap

A map of IDs to the old versions of the sObject records.
This map is only available in 
update and delete triggers.

operationType

Returns an enum of type System.TriggerOperation corresponding to the current Operation.

Possible values of the System.TriggerOperation enum are: BEFORE_INSERTBEFORE_UPDATEBEFORE_DELETE,AFTER_INSERT

AFTER_UPDATEAFTER_DELETE, and AFTER_UNDELETE

 

size


The total number of records in a trigger invocation, both old and new.

 

 

 Context Variable Availability for Trigger Events :

 

Events

Trigger.Old

Trigger.OldMap

Trigger.New

Trigger.NewMap

Before Insert

No

No

Yes

No

After Insert

No

No

Yes

Yes

Before Update

Yes

Yes

Yes

Yes

After Update

Yes

Yes

Yes

Yes

Before Delete

Yes

Yes

No

No

After Delete

Yes

Yes

No

No

After Undelete

No

No

Yes

Yes

 

Q1. What does one mean by the bulkifying trigger?

A trigger should be able to handle single record and thousands of records. important point to consider:

1.   Write triggers that operate on collections of sObjects.

2.   Write triggers that perform efficient SOQL and DML operations.

3.   If we will not follow above point we may hit governor limit when records are created/updated/deleted in mass using data loader or other tool.

  

Q2.How is Trigger.New Different from Trigger.newMap?

Trigger.New variable returns the list of sObject which has invoked the trigger and Trigger.NewMap returns the map of ID’s with the newly entered records. NewMap is only available in after insert, before and after the update and after undelete.

Q3.How is Trigger.new different from Trigger.old?

Trigger.New variable returns the list of sObject which has invoked the trigger and Trigger.old returns a list of the older versions of the records which have invoked the trigger. Trigger.Old is only available in update and delete events.

Q4. Can a trigger call a batch class?

Yes, we can call a batch class in the trigger. But Salesforce allows only 5 Batch jobs in the Queue.

Q5. Can a trigger make a call to Apex callout method?

We cannot call the callouts directly from the trigger, instead we will define callouts in the future annotated methods and these future annotated methods can be called from the trigger. We can only do 10 callouts in a single transaction.

Q6. Write a trigger for roll up summary on account object to sum the total contacts associated with an account.

 We have to create a custom field on account with the name "No_Of_Contacts__c".



 Q7. Write a trigger to prevent deletion of Account having contact associated with it.

or,


Q8. Write a trigger to display an error on Contact creation if the Account has more than 2 contacts.

Q9. Write a trigger to get sum of all the opportunities on Account.


First, we will create a custom field on Account “Total_Opportunity_Amount__c”.

 


 

Q10. Write a trigger on Account when type field value changed to “Prospect” else assign value as “Other”.

 

 

Q11. Trigger to create related contact when an account is created and associate that contact with accounts.


Q12. Write a trigger, Whenever the user Updates the Account Record, the Description of the Account Record will be changed to Logged in User Name.


Q13. whenever there is an update in account phone number, the related contact phone number should also get updated.


or



Q14. Apex trigger to update account rating to “Hot”,when the opportunity stage equals closed won.



 

Q15. Write a trigger, whenever new account is created with annual revenue more than 50 lakhs then add Wilson as account team member.




Q16.
When ever a case is created with origin as email then set status as new and Priority as Normal.



Q17. Whenever lead is created with leadSource as Web then give rating as cold otherwise hot.


 

Q18. Whenever opportunity stagename is modified to closed won then set closedate as today and type as new Customer.

  


 Q19. Whenever we are trying to delete the account record which has 

a contacts for it. Then deletion has to fail.

 

 

Q20. What is Recursive Trigger? And how to Avoid it.

 Ans : Recursion is the process of executing the same task multiple times. It can lead to infinite loop and which can result to governor limit sometime. Sometime it can also result in unexpected output or the error “maximum trigger depth exceeded”.

Ex: I’ve a trigger on Account object, which will be execute on before Update and after Update. In after Update I’ve some custom logic to update Account records. So, when I’m updating the Account records in After Update, it is throwing error “maximum trigger depth exceeded”. So, it is a recursion in apex trigger.

 

How to Avoid it:

We can create one static Boolean variable

 

public class AvoidRecursive {
   public static boolean firstRun = true;
}

 

and in trigger we can check the flag:

 

trigger TestTrigger on Contact (after insert) {
    if(AvoidRecursive.firstRun)
    {
        AvoidRecursive.firstRun = false;
        insert new Contact(Lastname=’Madhu’, Phone=12345);
    }  

 

Here first time we set Boolean variable as “TRUE” in class.  In trigger variable is equals to true then it goes to inside loop, performs logic and then variable sets as “FALSE” so next time it will not run (if variable=false then it will not go to loop & will not perform logic). So, if   Code will try to run second time in same request, then it will not run.

 

 There is one more way to avoid recursive trigger.

Create a new RecursiveCheck Class and add a static Set recordIds that will be used to store record Ids from trigger list.

 

Now in Trigger use recordIds set to check for the record ids on which the Trigger has already run like below: 

NOTE : Instead of checking the size before  DML in trigger. I.E

if(list.size().0)
{
//DML statements
}

We should use 

if(!list.isEmpty)
{
//DML statement
}

 It will save lot of resources. if we are using size() method, it will iterate over all the records, but do we really need to iterate over all those records ? NO.

So, Even if , we have 1 record, we need to perform DML, that's why, we should try to use isEmpty instead of size() method.


 Question : Scenario is, we have two objects(it can be standard or custom), both are in lookup relation. We are taking Account and contact objects

on Parent, we have below fields

1. Active_Contacts__c - total no. of contacts associated

2.Recently_completed_milestone__c - Date time field

on contact, we have "status" field.

Whenever status is changing from ongoing to completed, we need to stamp datetime on parent custom field. Also, we need to count no. of contacts associated with Account.

 


 Question : Suppose we have below requirement :

Account object :

Account fields : 

        Name : Salesforce Learners

        SLAserialNumber : SFDC01

        Active_Contacts__c = ?


Candidate object :

   Fields :

 Candidate Name =  Gaurav

SLAserialNumber = SFDC01

Account (lookup to Account) =  ?


Based on SLAserialNUmber( some code), we need to populate account on candidate which is look up to Account object. Also we need to populate number of candidates on Account.


Ans : To populate no. of candidates on Account, we have a custom field(Active_Contacts__c) on Account.

 SLAserialNumber__c is also custom field. It will be unique. we can consider it as code.



Question : Write a trigger to  When a related contact of an Account is created we have to consider following  scenarios:

  1. If the inserted contact is the first contact , then we need to mark it as primary contact for that related Account.

  2. If multiple contacts are already related to an Account, then the first contact which was created for that account has to be marked as  primary contact of the Account.

Solution : We have to create a custom checkbox field on contact as " primary Contact " Primary_Contact__c.


 

 

 

 

Duplicate id in list

  Error 'System.ListException: Duplicate id in list' in Apex : list  can hold  duplicate values, but if you try to add duplicate  sO...