0% found this document useful (0 votes)
12 views

Salesforce Developer Apex Basics & OOPs Concepts

Apex is a strongly typed, object-oriented programming language specifically designed for the Salesforce platform, allowing developers to create custom functionalities. Key features include server hosting, object-oriented support, strong typing, and integration with the database, along with built-in testing capabilities. Apex supports various constructs, data types, and collections, making it a versatile tool for cloud development and enhancing Salesforce applications.

Uploaded by

aaditya31001
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views

Salesforce Developer Apex Basics & OOPs Concepts

Apex is a strongly typed, object-oriented programming language specifically designed for the Salesforce platform, allowing developers to create custom functionalities. Key features include server hosting, object-oriented support, strong typing, and integration with the database, along with built-in testing capabilities. Apex supports various constructs, data types, and collections, making it a versatile tool for cloud development and enhancing Salesforce applications.

Uploaded by

aaditya31001
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 218

APEX

What is Apex?
Apex is a strongly typed, object-oriented programming language
that is designed specifically for the Salesforce platform.
It allows developers to create custom functionality, such as
triggers, controllers for Visualforce pages, batch processes,
workflows, and more, to extend and enhance the standard
capabilities of Salesforce applications.
Key Features of Apex?

➢Hosted—Apex is saved, compiled, and executed on the server—the


Lightning Platform.
➢Object oriented—Apex supports classes, interfaces, and inheritance.
➢Strongly typed—Apex validates references to objects at compile time.
➢Multi Tenant aware—Because Apex runs in a multi-tenant platform, it
guards closely against runaway code by enforcing limits, which
prevent code from monopolizing shared resources.
Key Features of Apex?
➢Integrated with the database—It is straightforward to access and
manipulate records. Apex provides direct access to records and their fields,
and provides statements and query languages to manipulate those records.
➢Easy to use—
➢Easy to test—Apex provides built-in support for unit test creation, execution,
and code coverage. Salesforce ensures that all custom Apex code works as
expected by executing all unit tests prior to any platform upgrades.
➢Versioned—Custom Apex code can be saved against different versions of
the API.
Salesforce Application Anatomy
Flow of Action
Constructs that Apex supports

➢ Classes, interfaces, properties, and collections (including arrays).


➢ Object and array notation.
➢ Expressions, variables, and constants.
➢ Conditional statements (if-then-else) and control flow statements (for
loops and while loops).
Apex supports for Salesforce

➢ Cloud development as Apex is stored, compiled, and executed in the cloud.


➢ Triggers, which are similar to triggers in database systems.
➢ Database statements that allow you to make direct database calls and
query languages to query and search data.
➢ Transactions and rollbacks.
➢ The global access modifier, which is more permissive than the public
modifier and allows access across namespaces and applications.
➢ Versioning of custom code.
Note: Apex is a case-insensitive language.
Code Editors

1. Salesforce Setup
2. Developer Console
3. Execute Anonymous window
4. Visual Studio Code
My First APEX Program

System.debug(‘Cloud Analogy’);
Escape characters (\’ , \n, \t)

\b (backspace), \t (tab), \n (line feed), \f (form feed), \r (carriage return), \"


(double quote), \' (single quote), and \\ (backslash)

String str = 'My team\'s name is \'Learnowx\'. \n We train on Salesforce.';


System.debug(str);

Output: My team's name is 'Learnowx'.


We train on Salesforce.
Comments

➢ Comments are used to annotate code to provide explanations,


documentation, or reminders for developers reading the code. There are two
types of comments in Apex
○ Single-Line Comments: Single-line comments begin with // and extend
to the end of the line. They are typically used for short explanations.
○ Multi-Line Comments: Multi-line comments begin with /* and end with
*/. They can span across multiple lines and are useful for longer
explanations.
Best Practices for Using Comments in Apex

➢ Use Comments Sparingly: Comments should be used to explain why the


code is written a certain way.
➢ Keep Comments Updated: Maintain comments to reflect changes in the
code. Outdated comments can be misleading and should be revised or
removed as necessary.
➢ Be Clear and Concise: Write clear and concise comments that enhance
understanding without duplicating the code's functionality.
➢ Use Comment Formatting: Format comments consistently to improve
readability and maintainability of the codebase.
Data Type in APEX
1. Primitive Data Types: Apex uses the same primitive data types as SOAP
API, except for higher-precision Decimal type in certain cases. All
primitive data types are passed by value.
2. Collections: Collections in Apex can be lists, sets, or maps.
3. Enums: An enum is an abstract data type with values that each take on
exactly one of a finite set of identifiers that you specify.
4. sObjects: Standard and custom objects.
Primitive Data Types

Data Type Description

Boolean A value that can only be assigned true, false, or null

Date A value that indicates a particular day. Unlike Datetime values, Date
values contain no information about time. Date Class

Datetime A value that indicates a particular day and time, such as a timestamp.
Date Time Class

Decimal A number that includes a decimal point. Decimal is an arbitrary


precision number. Currency fields are automatically assigned the type
Decimal. Use the setScale method to set a Decimal’s scale. Example
Primitive Data Types

Data Type Description

Double A 64-bit number that includes a decimal point. Doubles have a


minimum value of -263 and a maximum value of 263-1. For example:
Double pi = 3.14159;

ID Any valid 18-character Lightning Platform record identifier.

Integer A 32-bit number that doesn’t include a decimal point. Integers have
a minimum value of -2,147,483,648 and a maximum value of
2,147,483,647.

Long A 64-bit number that doesn’t include a decimal point. Longs have a
minimum value of -263 and a maximum value of 263-1
Primitive Data Types
Data Type Description

Object Any data type that is supported in Apex. Apex supports primitive data
types (such as Integer), user-defined custom classes, the sObject
generic type, or an sObject specific type (such as Account). All Apex
data types inherit from Object.
You can cast an object that represents a more specific data type to
its underlying data type.
Object obj = 10;
Integer i = (Integer)obj;

String Any set of characters surrounded by single quotes. Strings have no


limit on the number of characters they can include. Instead, the heap
size limit is used.

Time A value that indicates a particular time. Time Class


Primitive Data Types (Blob)
➢ Using this you can store files like videos, images, gifs, and audio files.
➢ The Blob (binary large object) is a collection of Binary data which is stored as
object. This will be used when we want to store the attachment in salesforce into
a variable. This data type converts the attachments into a single object. If the
blob is to be converted into a string, then we can make use of the toString and
the valueOf methods for the same.
➢ A BLOB (binary large object) is a varying-length binary string that can be up to
2,147,483,647 characters long. Like other binary types, BLOB strings are not
associated with a code page. In addition, BLOB strings do not hold character
data.
Primitive Data Types
String greeting = 'Hello World'; Long worldPopulation = 7000000000L;
System.debug(greeting); System.debug(worldPopulation);

Boolean amIAwake = true; Double lightSpeed = 93000000/186000;


System.debug(amIAwake); System.debug(lightSpeed);

Integer rollNumber = 11008890; Decimal currency = 35.56;


System.debug(rollNumber); System.debug(currency);
String Class
➢ String Class contains methods for the String primitive data type.

Method Description Syntax

capitalize() Returns the current String with the first letter str.capitalize();
changed to title case

charAt(index) Returns the value of the character at the str.charAt(0);


specified index

contains(substring) Returns true if and only if the String that called myString1.contains(my
the method contains the specified sequence of String2);
characters in substring.

deleteWhitespace() Returns a version of the current String with all str.deleteWhiteSpace()


white space characters removed
String Class
Method Description Syntax

length() Returns the number of 16-bit Unicode str.length()


characters contained in the String.

remove(substring) Removes all occurrences of the specified str.remove(substring)


substring and returns the String result.

toUpperCase() Converts all of the characters in the String to str.toUpperCase()


uppercase.

toLowerCase() Converts all of the characters in the String to str.toLowerCase()


lowercase.

equals(stringOrId) Returns true if the passed-in object is not null str.equals(myId)


and represents the same binary sequence of
characters as the current string.
String Class
Method Description Syntax

isWhitespace() Returns true if the current String contains only str.isWhitespace()


white space characters or is empty; otherwise,
returns false.

replace(target, Replaces each substring of a string that str.replace('ring', 'rong')


replacement) matches the literal target sequence target with
the specified literal replacement sequence
replacement.

split(regExp) Returns a list that contains each substring of str.split(' ')


the String that is terminated by either the
regular expression regExp or the end of the
String.

String Class Reference


APEX COLLECTIONS
➢A collection is a type of variable that can store multiple items. In Apex we
have following types of collections:
■ List
■ Set
■ Map
List

➢Lists hold an ordered collection of objects. Lists in Apex are synonymous with
arrays and the two can be used interchangeably.
➢The following two declarations are equivalent. The colors variable is declared
using the List syntax.
· List<String> colors = new List<String>();
➢ Alternatively, the colors variable can be declared as an array but assigned to a
list rather than an array.
· String[] colors = new List<String>();

List<String> colors = new List<String> { 'red', 'green', 'blue' };


System.debug(colors);
List Methods
Method Description Syntax
add(listElement) Adds an element to the end of the list. myList.add(10);

add(index, Inserts an element into the list at the specified myList.add(2,30);


listElement) index position.

addAll(fromList) Adds all of the elements in the specified list to intList.addAll(myList);


the list that calls the method. Both lists must be
of the same type.

addAll(fromSet) Add all of the elements in specified set to the intList.addAll(mySet);


list that calls the method. The set and the list
must be of the same type.

clear() Removes all elements from a list, consequently myList.clear();


setting the list's length to zero.
List Methods
Method Description Syntax
clone() Makes a duplicate copy of a list. myList.clone();

contains(list Returns true if the list contains the specified myList.contains(72)


Element) element.

equals(list2) Compares this list with the specified list and myList.equals(newList)
returns true if both lists are equal; otherwise,
returns false.

get(index) Returns the list element stored at the specified myList.get(2)


index.

indexOf(listE Returns the index of the first occurrence of the myList.indexOf(12)


lement) specified element in this list. If this list does not
contain the element, returns -1.
List Methods

Method Description Syntax


isEmpty() Returns true if the list has zero elements. myList.isEmpty()

remove(index) Removes the list element stored at the specified myList.remove(2)


index, returning the element that was removed.

set(index, Sets the specified value for the element at the myList.set(2,10)
listElement) given index.

size() Returns the number of elements in the list. myList.size()

sort() Sorts the items in the list in ascending order. myList.sort();

toString() Returns the string representation of the list. String s =


myList.toString();
List

➢List elements can be read by specifying an index between square brackets,


just like with array elements.
➢Also, you can use the get() method to read a list element.
// Get elements from a list
String color1 = moreColors.get(0);
String color2 = moreColors[1];
System.assertEquals(color1, color2, 'Not matching');

Note: assertEquals(expected, actual, msg)


List

List of Accounts (sObject)

List<account> Acc = new List<account> (); //This will be null


System.debug('Value in Account —'+Acc);
SET in APEX
➢Set is an unordered collection of elements of similar data type.
➢No duplicate value is allowed

Syntax
Set <datatype> setVar = new Set<datatype>{value1,value2,...value n};

Set<Integer> marks = new Set<Integer>{11008890, 11008100, 11007231};


System.debug(marks);
Set Methods
Method Description Syntax
add(setElement) Adds an element to the set if it is not already mySet.add(10);
present.

addAll(fromList) Adds all of the elements in the specified list to intSet.addAll(myList);


the set if they are not already present.

addAll(fromSet) Adds all of the elements in the specified set to intSet.addAll(mySet);


the set that calls the method if they are not
already present.

clear() Removes all of the elements from the set. mySet.clear();


Set Methods
Method Description Syntax
clone() Makes a duplicate copy of a set. mySet.clone();

contains(setEl Returns true if the set contains the specified mySet.contains(72)


ement) element.

containsAll(list Returns true if the set contains all of the elements in myList.containsAll(
ToCompare) the specified list. The list must be of the same type newList)
as the set that calls the method.

containsAll(set Returns true if the set contains all of the elements in myList.containsAll(
ToCompare) the specified set. The specified set must be of the newSet)
same type as the original set that calls the method.
Set Methods

Method Description Syntax


isEmpty() Returns true if the set has zero elements mySet.isEmpty()

remove(setElemen Removes the specified element from the set if mySet.remove(20)


t) it is present.

removeAll(listOfEl Removes the elements in the specified list mySet.removeAll(my


ementsToRemove) from the set if they are present. List)

removeAll(setOfEl Removes the elements in the specified set mySet.removeAll(my


ementsToRemove) from the original set if they are present. Set)

retainAll(listOfEle Retains only the elements in this set that are mySet.retainAll(myLi
mentsToRetain) contained in the specified list. st)
Set Methods

Method Description Syntax


retainAll(setOfEle Retains only the elements in the original set mySet.retainAll(mySe
mentsToRetain) that are contained in the specified set. t)

size() Returns the number of elements in the set mySet.size()

toString() Returns the string representation of the set. String s =


mySet.toString();
Set

Example: Store Ids of Account in a Set.

public class SetClass {

public void Example1() {


List<Account> accList = new List<Account>();
Set<Id> accIds = new Set<Id>();
accList = [SELECT Id, Name FROM Account LIMIT 2];

for (Account acc: accList){


accIds.add(acc.Id);
}
}
}
Map
➢A Map is a collection of key-value pairs where each unique key maps to a
single value.
➢It stores the data in key-value pair. e.g. (Roll Number, Name).
➢Map keys and values can be of any data type—primitive types, collections,
sObjects, user-defined types, and built-in Apex types.
➢Map keys of type String are case-sensitive.
Map<Integer, String> Students = new Map<Integer, String>();
Map Methods

Method Description Syntax


put(key, value) Associates the specified value with the myMap.put(1, 'Salesforce');
specified key in the map.

putAll(fromMap) Copies all of the mappings from the myMap.putAll(newMap)


specified map to the original map.

putAll(sobjectAr Adds the list of sObject records to a map myMap.putAll(sObjectList)


ray) declared as Map<ID, sObject> or
Map<String, sObject>.

remove(key) Removes the mapping for the specified myMap.remove(101)


key from the map, if present, and returns
the corresponding value.
Map Methods

Method Description Syntax


size() Returns the number of key-value pairs in myMap.size();
the map.

toString() Returns the string representation of the myMap.toString()


map.

values() Returns a list that contains all the values myMap.values()


in the map.

clear() Removes all of the key-value mappings myMap.clear()


from the map

clone() Makes a duplicate copy of the map myMap.clone()


Map Methods
Method Description Syntax
containsKey(key) Returns true if the map contains a mapping for myMap.contains
the specified key. Key(201)

equals(map2) Compares this map with the specified map and myMap.equals(n
returns true if both maps are equal; otherwise, ewMap)
returns false.

get(key) Returns the value to which the specified key is myMap.get(200


mapped, or null if the map contains no value for 2)
this key.

isEmpty() Returns true if the map has zero key-value myMap.isEmpty(


pairs. )

keySet() Returns a set that contains all of the keys in the myMap.keySet()
map.
Map

Map<Integer, String> Students = new Map<Integer, String>();

// add new items


Students.put(11008890, 'Mohit');
Students.put(11008891, 'Harry');
Students.put(11008892, 'Rick');
Students.put(11008893, 'Bill');
System.debug(Students);
Map
// with sObjects

List<Account> accList = new List<Account>();


accList = [SELECT name, Id FROM Account LIMIT 2];
Map<Id,Account> accIdMap = new Map<Id,Account>(accList);
System.debug(accIdMap);

Or

Map<Id,Account> accIdMap = new Map<Id,Account>( [SELECT name,


Id FROM Account LIMIT 2]);
System.debug(accIdMap);
Enum
➢An enum is an abstract data type with values that each take on exactly one
of a finite set of identifiers that you specify.
➢Enums are typically used to define a set of possible values that don’t
otherwise have a numerical order.
➢To define an enum, use the enum keyword in your declaration and use curly
braces to demarcate the list of possible values.

public enum Season {WINTER, SPRING, SUMMER, FALL}


Season todaysSeason = Season.WINTER;
System.debug(todaysSeason);
Enum
➢An enum has the following methods:
■ values() → Return the list of values in enum.
■ ordinal() → Return the position of a particular value in enum.
■ name() → Return the value as a string.
■ valueOf() → Convert the string value into enum value.
Enum Example
public class SalesforceDemo {
public enum color {RED,GREEN,BLUE,BLACK,ORANGE}
public void dispalyName(){
List<color> colList = color.values();
System.debug(colList); // (RED, GREEN, BLUE, BLACK, ORANGE)
System.debug(color.BLUE.ordinal()); // 2--> position of BLUE in enum
System.debug(color.ORANGE.name()); // return ORANGE as string
System.debug('ORANGE'.equals(color.ORANGE.name())); // true
color blueColor = color.valueOf('BLUE');
System.debug(blueColor); // BLUE
}
}
sObject in APEX
➢Any Standard or Custom object is an sObject.
➢Sobjects are specific subtype that represents database records, including
standard objects like Accounts and Cases, custom objects, custom settings,
and custom metadata.

Account acc;

➢Every record in Salesforce is natively represented as an sObject in Apex.


■ Specific sObject such as an Account, Contact,
■ CustomObject__c
sObject in APEX
➢For custom objects and custom fields, the API name always ends with the
__c suffix.
➢For custom relationship fields, the API name ends with the __r suffix.

Create sObjects and Adding Fields

Account acct = new Account(Name='ABC Limited',


Phone='(011)121-3434', NumberOfEmployees=100);
sObject in APEX
Specific sObject vs Generic sObject Data Type
Account acct = new Account(Name='Sam'); // Specific sObject

sObject sobj1 = new Account(Name='Ginee'); //Generic sObject

➢For specific sObject fields can be accessed by using (.) dot.


➢For generic sObject fields can be accessed through the put() and get() methods.
➢sobj1.get(‘Name’);
➢We can get the sObject type by using getSObjectType() method.
■ sobj1.getSObjectType()
Constants

➢A constant variable once initialized does not change its value.


➢Constants can be defined using the final keyword.

final Decimal PI = 3.14159;


Operators

// assignment operator
Integer x = 5;

System.debug('assignment operator - '+x);


Operators
// addition operator // multiplication operator

x = x + 5; x = x * 5;

System.debug('addition operator - '+x); System.debug('multiplication operator - '+x);

// Subtraction operator // division operator

x = x - 5; x = x/5;

System.debug('Subtraction operator - System.debug('division operator - '+x);


'+x);
Operators
// addition assignment operator // multiplication assignment operator

x += 5; x *= 5;

// subtraction assignment operator // division assignment operator

x -= 5; x /= 5;
Operators
// using addition operator on strings

String hello = 'Hello';

String world = 'World';

System.debug(hello + world); //HelloWorld

System.debug(hello + ' ' + world); //Hello World


Operators
//AND Operator // Greater than operator

result = first && second; result = (5 > 6);

//OR Operator //less than or equal to operator

result = first || second; result = (5 <= 6);

// Equality operator //greater than or equal to operator

result = (first == second); result = (5 >= 6);

// Less than operator // NOT operator

result = (5 < 6); val = !val;


Operators

//decrement operator
//increment operator
X - - ; //
x++;
System.debug('decrement operator - '+x);
System.debug('increment operator - '+x);
Operators

// Ternary operator

String greeting = ' ';

Integer hour = 10;

// if hour is less than 12, then greeting should be good morning

// else greeting should be good afternoon

greeting = (hour < 12) ? 'Good Morning' : 'Good Afternoon';

System.debug('Ternary operator 10 - '+ greeting);


Type Conversion
➢Type conversion (also known as type casting) refers to the process of
converting a value from one data type to another. There are two types of
type conversion
■ Implicit Type Conversion
■ Explicit Type Conversion
Implicit Type Conversion
➢Apex performs implicit type conversion automatically when it can safely
convert one data type to another without losing information or causing
errors.
➢Example:
Integer myInt = 20;
System.debug('Integer Value: '+myInt);
Decimal myDeci = myInt;
System.debug('Decimal value: '+myDeci.setScale(2));

➢In this example, myInt of type Integer is implicitly converted to myDeci of


type Decimal
Explicit Type Conversion
➢Explicit type conversion is done explicitly by the developer using casting.
This is necessary when Apex cannot automatically convert types or when
you want to ensure a specific type conversion
➢Example:
Decimal myDeci = 20.65;
System.debug('Decimal Value: '+myDeci);
Integer myInt = (Integer) myDeci;
System.debug('Integer value: '+myInt);

➢In this case, the (Integer) syntax explicitly casts the Decimal value myDeci
to an Integer.
Type Conversion Methods
➢String to Integer: Use Integer.valueOf(String).
Integer.valueOf('65675665')
➢String to Decimal: Use Decimal.valueOf(String).
Decimal.valueOf('656756.65')
➢Integer to String: Use String.valueOf(Integer) or Integer.toString().
String str = String.valueOf(54665455);
➢Decimal to String: Use String.valueOf(Decimal) or Decimal.toString().
String str = String.valueOf(6576577.87);
➢Date/DateTime to String: Use String.valueOf(Date).
Date myDate = Date.valueOf('2024-05-24');
String str = String.valueOf(myDate);
Type conversion Examples

Example 1: String a = '55';


Integer c = Integer.valueOf(a);

Example 2: String a = '55';


String b = ‘35’;
String c = String.valueOf(Integer.valueOf(a) + Integer.valueOf(b));
Control Flow Statements
➢Conditional (If-Else) Statements: The conditional statement in Apex
works similarly to Java.

if ([Boolean_condition]) if (place == 1)
// Statement 1 { medal_color = 'gold'; }
else // Statement 2 else if (place == 2)
{ medal_color = 'silver’; }
else if (place == 3)
{ medal_color = 'bronze'; }
else { medal_color = null; }
Control Flow Statements
➢Switch Statements: Apex provides a switch statement that tests whether an
expression matches one of several values and branches accordingly.
switch on expression {
when value1 {
// when block 1
}
when value2 {
// when block 2
}
when value3 {
// when block 3
}
when else {
// default block, optional
}
}
Control Flow Statements
When Blocks:

➢Each when block has a value that the expression is matched against.
These values can take one of the following forms:
➢when literal {}
➢when SObjectType identifier {}
➢when enum_value {}
➢The value null is a legal value for all types
Control Flow Statements
Examples with Literals Null Value Example Multiple Values Examples
switch on i { switch on i { switch on i {
when 2 { when 2 { when 2, 3, 4 {
System.debug('when block 2'); System.debug('when block System.debug('when block 2 and
} 2'); 3 and 4');
when -3 { } }
System.debug('when block -3'); when null { when 5, 6 {
} System.debug('bad System.debug('when block 5 and
when else { integer'); 6');
System.debug('default'); } }
} when else { when 7 {
} System.debug('default ' + System.debug('when block 7');
i); }
} when else {
} System.debug('default');
}
}
Control Flow Statements
Method Example Example with sObjects Example with Enums

switch on someInteger(i) { if (sobject instanceof Account) { switch on season {


when 2 { Account a = (Account) sobject; when WINTER {
System.debug('when block System.debug('account ' + a); System.debug('boots');
2'); } else if (sobject instanceof }
} Contact) { when SPRING, SUMMER {
when 3 { Contact c = (Contact) sobject; System.debug('sandals');
System.debug('when block System.debug('contact ' + c); }
3'); } else { when else {
} System.debug('default'); System.debug('none of the
when else { } above');
System.debug('default'); }
} }
}
Loop Statements
➢ do {statement} while (Boolean_condition);
➢ while (Boolean_condition) statement;
➢ for (initialization; Boolean_exit_condition; increment) statement;
➢ for (variable : array_or_set) statement;
➢ for (variable : [inline_soql_query]) statement;

All loops allow for loop control structures:


○break: exits the entire loop
○continue: skips to the next iteration of the loop
Loop Statements
do-While Loops
do {
code_block
} while (condition);

Integer count = 1;
do { System.debug(count);
count++;
} while (count < 11);
Loop Statements
While Loops
while(condition)
{
code_block
}

Integer count = 1;
while (count < 11) {
System.debug(count);
count++;
}
Loop Statements

Traditional For Loops

for (init_stmt; exit_condition; increment_stmt) {


code_block
}

for (Integer i = 0, j = 0; i < 10; i++)


{
System.debug(i+1);
}
Loop Statements
List or Set Iteration for Loops
for (variable : list_or_set)
{
code_block where variable must be of the same
} primitive or sObject type as list_or_set.

Integer[] myInts = new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

for (Integer i : myInts) {


System.debug(i);
}
Script for Pattern
public class Pattern1 {
public static void P1(integer n){
for(integer i=1;i<=n;i++)
{
string s=' ';
for(integer j=1;j<=i;j++)
{
s= s+'*';

}
system.debug(s);

*
} **
} ***
****
} *****
Script for Pattern
public class Pattern1 {
public static void P1(integer n){
for(integer i=1;i<=n;i++)
{
string s=' ';
for(integer j=i;j<=n;j++)
{
s= s+'x';

}
system.debug(s);
*****
****
} ***
}
**
} *
Script for Pattern
public class Pattern1 {
public static void P1(){
for(integer i=1;i<=5;i++){
string s=' ';
boolean k=true;

for(integer j=1;j<=9;j++) {
if(j>=i && j<=10-i && k){
s = s + 'x';
k=false;
}
else{ *****
s = s + '_'; ****
k=true; ***
}
}
**
system.debug(s); *
}
}
Classes & Objects in Apex

➢ Object Oriented Programming is a programming paradigm which wraps the

pieces of data (fields), and behaviours (methods) related to data into special

term called Objects.

➢ Object - Any real world entity is an object and every object have state (fields)

and behaviours (methods). Objects are instance for any class.

➢ Class - Class is a blueprint which defines the structure for the objects.
Apex Class

➢ Objects Properties

➢ Classes Name
RollNumber
Age
○ Properties

○ Behaviour
Behaviour
markAttendance()
getAttendance()
payFee()
Apex Class

public class HelloWorld { /*To execute above class, use below code in
String greeting = 'Hello World'; anonymous window of dev console*/

public void printGreeting() { HelloWorld firstClass = new HelloWorld();


System.debug(greeting);
} firstClass.printGreeting();

public void showGreeting();


//method
signature/prototype/declaration
}
Apex Class Definition
Syntax

private | public | global


[virtual | abstract | with sharing | without sharing]
class ClassName [implements InterfaceNameList] [extends ClassName]
{
// The body of the class
}
Apex Class
Task: Write an Apex Class to convert Fahrenheit temperature to Celsius.

public class TemperatureConverter


{
public static decimal fahrenheitToCelsius(Decimal f)
{
Decimal c = (f-32)*5/9;
return c.setScale(2);
}
}
Access Modifiers in Apex

➢ Private

➢ Protected

➢ Public

➢ Global
Access Modifiers in Apex

Private:

➢ Visibility: only in class in which it is declared

➢ Default access modifier

➢ Can be used with variables, methods and inner classes

➢ Private variable can only be accessed by class methods

➢ Can not be used with outermost class


Access Modifiers in Apex

Protected:

➢ Visibility: only in class in which it is declared and the class that extends this

class

➢ Can be used with variables and methods

➢ Inner classes and classes that extend outer class can access these variables

and methods

➢ Its use in Apex is very rare.


Access Modifiers in Apex

Public:

➢ Visibility: If a class is public then its content is visible to all classes in the org.

➢ Can be used with classes, methods and variables.

➢ Accessible to all classes and methods within Namespace.


Access Modifiers in Apex

Global:

➢ No Difference in Public and Global if the classes are in the same org. But, if

class A is public and class B is Global and both the classes are in a package in

AppExchange and you are using this package in your org then content of class

A will not be visible but content of class B will be visible in your org.

➢ Accessible to all classes and methods, even in other Namespaces as well.


Apex Methods
To define a method in Apex, specify the following:

➢ Optional: Modifiers, such as public or protected.


➢ Required: Returned type of the method, such as String or Integer. Use void if the
method doesn’t return a value.
➢ Required: A list of input parameters for the method, separated by commas,
each preceded by its data type, and enclosed in parentheses (). If there are no
parameters, use a set of empty parentheses. A method can only have 32 input
parameters.
➢ Required: The body of the method, enclosed in braces {}.
Apex Methods

public static Integer add(Integer number1, Integer number2)


{
Integer sum = number1 + number2;
return sum;
}
Constructors
➢ A constructor is code that is invoked when an object is created from the class
blueprint.
➢ If a class does not have a user-defined constructor, a default, no-argument, public
constructor is used.
➢ The syntax for a constructor is similar to a method, but it differs from a method
definition in that it never has an explicit return type.
➢ Constructor has the same name as the class name.
➢ Invokes automatically when instance is created.
➢ Constructors can not return anything as they are automatically called.
Constructors
public class Covid19{
public Integer NumberOfPatientInCity = 0;
public static Integer NumberOfPatientInCountry = 0;
public Covid19() // Default CONSTRUCTOR
{
System.debug('blank constructor');
}
public Covid19(Integer numberOfPatient) // parameterized CONSTRUCTOR
{
this.NumberOfPatientInCity = numberOfPatient;
NumberOfPatientInCountry += numberOfPatient;
}
public void display()
{
System.debug('Number of Cases in city: '+this.NumberOfPatientInCity);
System.debug('Number of Cases in Country: '+NumberOfPatientInCountry);
}
}
Constructors
➢ Once you create a constructor for a class, you no longer have access to the
default, no-argument public constructor.
➢ If you create a constructor that takes arguments, and you still want to use a
no-argument constructor, you must create your own no-argument constructor in
your code.
➢ A constructor can be overloaded, that is, there can be more than one constructor
for a class, each having different parameters.
Object Oriented Programming Concepts
➢ Following are the four pillars of Object-Oriented programming language:
○ Abstraction – Hiding internal details and showing only the functionality is known
as abstraction.
○ Inheritance – In Allows a class (subclass/child class) to inherit properties and
methods from another class (superclass/parent class). Apex supports single
inheritance
○ Polymorphism – Polymorphism is a concept which describes the process of
performing a single action in different ways. You can declare multiple methods
with the same name until they have different characteristics or parameters.
○ Encapsulation – Ability to bind data and behavior together.
Abstraction
➢ Focuses on hiding the complexity and only showing the essential features of an
object.
➢ Achieved through abstract classes (cannot be instantiated, can have abstract
methods) and interfaces (contains method signatures only).
Abstract Class
➢ An abstract class is a blueprint for other classes and cannot be instantiated on its
own.
➢ To define an abstract class we use abstract keyword.
➢ Abstract class can have both abstract and virtual (non abstract) methods.
➢ All the abstract methods must be implemented inside the child class.
➢ Example:
public abstract class MyClass {
public virtual void method1(){
System.debug('This is non abstract method');
}
public abstract void method2();
}
Interface
➢ An interface is like a class in which none of the methods have been implemented.
➢ Interface is used to achieve full Abstraction.
➢ To create an interface we need to use the interface keyword.
➢ To use an interface, another class must implement (implements keyword) it by
providing a body for all of the methods contained in the interface.
➢ Example:
public interface PurchaseOrder {
Double discount();
}
Interface
public class CustomerPurchaseOrder implements PurchaseOrder {

public Double discount() {

return .05; // Flat 5% discount


public interface PurchaseOrder {
}
Double discount();

public class EmployeePurchaseOrder implements PurchaseOrder {

public Double discount() {

return .10; // an employee! 10% discount

}
Abstract Class vs Interface
Abstract Class Interface
Abstract class can have abstract and non-abstract Interface can have only abstract methods.

methods.

Abstract class doesn't support multiple inheritance. Interface supports multiple inheritance.

Abstract class can provide the implementation of Interface can't provide the implementation of

interface. abstract class.

The abstract keyword is used to declare abstract The interface keyword is used to declare interface.

class.
Inheritance
➢ Capability to create a new class which will contain functionality of parent
class
➢ You can change existing method
➢ You can add some more method without impacting parent class methods
➢ Parent class and methods to be overridden must be declared virtual/abstract.
➢ Child class must use extends keyword
➢ Extending class can override the existing virtual/abstract methods by using
the override keyword in the method definition.
Virtual & Abstract Class
➢ Both virtual and abstract classes allow you to extend the class (i.e. create
child classes that inherit non-private methods and variables).
➢ Methods in virtual class CAN be overridden in derived classes, while
abstract class methods MUST be overridden.
➢ A virtual class can be instantiated directly, whereas an abstract class
cannot.
➢ Both virtual and abstract classes can contain virtual methods (virtual
methods can have a default implementation that is inherited by child
classes, whereas abstract methods can only be signatures, and must be
implemented in child classes).
Inheritance
Example1:

public class MyChildClass extends MyClass {


public virtual class MyClass {
public void fun2(){
public void fun1(){
System.debug('We are in Child Class');
System.debug('we are in parent class');
}
}
}
}
Inheritance

public virtual class Marker {


public class YellowMarker extends Marker {
public virtual void write() {
public override void write() {
System.debug('Writing some text.');
System.debug('Writing some text using the
}
yellow marker.');
public virtual Double discount() {
}
return .05;
}
}

}
Inheritance Important Points
➢ A class that extends another class inherits all the methods and properties of the
extended class. In addition, the extending class can override the existing virtual
methods by using the override keyword in the method definition.

➢ Overriding a virtual method allows you to provide a different implementation for an


existing method. This means that the behavior of a particular method is different based
on the object you’re calling it on. This is referred to as polymorphism.

➢ A class extends another class using the extends keyword in the class definition.

➢ A class can only extend one other class, but it can implement more than one interface.

➢ Use the virtual keyword, only classes with virtual can be extended

➢ Mark the method and class as virtual

➢ Extending class can override and provide a new definition to the virtual method
Inheritance Task
Create a school application with a class called Person. Create name and
dateOfBirth as member variables.

Create a class called Teacher that inherits from the Person class. The teacher will
have additional properties like salary, and the subject that the teacher teaches.

Create a class called Student that inherits from Person class. This class will have
a member variable called studentId.

Create a class called College Student that inherits from Student class. This class
will have collegeName, the year in which the student is studying
(first/second/third/fourth) etc.

Create objects of each of these classes, invoke and test the methods that are
available in these classes.
Polymorphic Methods
Example 2:

public class shape


{
public static Double area(Integer x, Integer y)
{
Double ar = x*y;
return ar;
}
public static Double area(Integer x)
{
Double ar = x*x;
return ar;
}
}
Polymorphic Methods

Task: Write script to find area of different figures (Rectangle, Square,


Triangle) using Polymorphic methods.
With Sharing & Without Sharing
➢ Use the with sharing or without sharing keywords on a class to specify
whether or not to enforce sharing rules.
➢ with sharing: Use the with sharing keyword when declaring a class to enforce
sharing rules of the current user. Explicitly setting this keyword ensures that
Apex code runs in the current user context.
➢ without sharing: Without Sharing means you are disabling or ignoring sharing
rules. Use the without sharing keyword when declaring a class to ensure that
the sharing rules for the current user are not enforced. For example, you can
explicitly turn off sharing rule enforcement when a class is called from
another class that is declared using with sharing.
Static Block
➢ Static block executes automatically when the class is loaded in memory.
➢ It executes even before calling of constructor.

public class MyClass {

static // Static block

System.debug('We are in Static Block.');

public MyClass(){ // constructor

System.debug('We are in Constructor Block.');

}
Static Variable
➢ Static variable belongs to class and not to instance of it.
➢ So only one copy of a static variable is created and shared among various
instances while a separate normal variable is created for each instance variable.
public class covid19{

public Integer NumberOfPatientInCity = 0;

public static Integer NumberOfPatientInCountry = 0; //static variable

public void patientNew( ){

NumberOfPatientInCity++;

NumberOfPatientInCountry++;

}
Static Variable

covid19 Noida = new covid19();

System.debug('Patient in Noida: '+Noida.NumberOfPatientInCity);

System.debug('Patient in Country: '+covid19.NumberOfPatientInCountry);

Noida.patientNew();

System.debug('Patient in Noida: '+Noida.NumberOfPatientInCity);

System.debug('Patient in Country: '+covid19.NumberOfPatientInCountry);


Static Variable

covid19 Delhi = new covid19();

Delhi.patientNew();

System.debug('Patient in Delhi: ' +Delhi.NumberOfPatientInCity);

System.debug('Patient in Country: '+covid19.NumberOfPatientInCountry);


Static Methods
➢ Static methods are easier to call than instance methods because they don’t need
to be called on an instance of the class but are called directly on the class name.
public class covid19{
public Integer NumberOfPatientInCity = 0;
public static Integer NumberOfPatientInCountry = 0; //static variable
public void patientNew( )
{
NumberOfPatientInCity++;
NumberOfPatientInCountry++;
}
public static void display() //static method
{
System.debug('Number of Cases in Country: '+numberOfPatientInCountry);
}
}
Static vs Instance

Static methods, variables, and initialization code have these characteristics.


➢ They’re associated with a class.
➢ They’re allowed only in outer classes.
➢ All instances of the same class share a single copy of the static variable.
➢ A class static variable can’t be accessed through an instance of that class.
➢ They’re initialized only when a class is loaded.
➢ They aren’t transmitted as part of the view state for a Visualforce page.

Instance methods, member variables, and initialization code have these characteristics.

➢ They’re associated with a particular object.


➢ They’re created with every object instantiated from the class in which they’re
declared.
Static vs Instance

Capability Static Instance


(Variable or Methods) (Variable or Methods)
Association Class Based Object based

Replication Only one copy One copy per instance

Initialization When class is loaded When instance is created

Syntax MyClass.staticMethod(); MyClass obj = MyClass();


obj.instanceMethod();
Using final Keyword
➢ Final variables can only be assigned a value once, either when you declare a variable or
inside a constructor. You must assign a value to it in one of these two places.

➢ Static final variables can be changed in static initialization code or where defined.

➢ Member final variables can be changed in initialization code blocks, constructors, or


with other variable declarations.

➢ To define a constant, mark a variable as both static and final.

➢ Non-final static variables are used to communicate state at the class level (such as
state between triggers). However, they are not shared across requests.

➢ Methods and classes are final by default. You cannot use the final keyword in the
declaration of a class or method. This means they cannot be overridden. Use the virtual
keyword if you need to override a method or class.
Using instanceof Keyword
➢ Use instanceof keyword to verify at
run time whether an object is actually
In Apex saved with API version 32.0 and later,
an instance of a particular class.
instanceof returns false if the left operand is a null
if (Reports.get(0) instanceof CustomReport) { object. For example, the following sample returns false.
// Can safely cast it back to a custom report object
CustomReport c = (CustomReport) Reports.get(0); Object obj = null;
} else {
Boolean result = obj instanceof Account;
// Do something with the non-custom-report.
System.assertEquals(false, result);
}

In API version 31.0 and earlier, instanceof returns true


in this case.
this in Apex

➢ We can use the this keyword in dot notation, without parenthesis, to represent the
current instance of the class in which it appears. Use this form of the this keyword to
access instance variables and methods.

➢ We can use the this keyword to do constructor chaining, that is, in one constructor,
call another constructor.
Using this Keyword
public class TrainingDemo {
String name;
Integer age;
public TrainingDemo(String name, Integer age){
this.name = name;
this.age = age;
}
public void display(){
System.debug('The name is '+this.name+' and age is '+this.age);
}
}
Using this Keyword
Use 2: Use this keyword to do constructor chaining, that is, in one constructor, call another constructor. In this
format, use the this keyword with parentheses. For example:

public class testThis {

// First constructor for the class. It requires a string parameter.

public testThis(string s2) {

// Second constructor for the class. It does not require a parameter.

// This constructor calls the first constructor using the this keyword.

public testThis() {
Note: When you use the this keyword in
this('None');
a constructor to do constructor
} chaining, it must be the first statement
in the constructor.
}
super in Apex

➢ The super keyword can be used by classes that are extended from virtual or abstract
classes.

➢ By using super, we can override constructors and methods from the parent class.
Using super to Access Constructor
➢ Super can be used to call the constructor of the parent class.

// Here we are using getter to get the public class Student extends Person{
values
String studentId;
public virtual class Person { public Student(String studentId,
String name; String name, Integer age){
Integer age; super(name, age);
public Person(String name, Integer this.studentId = studentId;
age){ }
this.name = name; public void
this.age = age; displayStudentInfo(){
} System.debug('Student Id is:
public String getName(){ '+this.studentId+' name is:
return this.name; '+this.getName()+' age is:
} '+this.getAge());
public Integer getAge(){ }
return this.age; }
}
}
Using super to Access Constructor
➢ If you don’t want to access it through getter then make the property as public

public virtual class Person { public class Student extends Person{


public String name; String studentId;
public Student(String studentId,
public Integer age; String name, Integer age){
public Person(String name, Integer super(name, age);
this.studentId = studentId;
age){
}
this.name = name; public void
this.age = age; displayStudentInfo(){
System.debug('Student Id is:
}
'+this.studentId+' name is:
} '+this.name+' age is: '+this.age);
}
}
Using super to Access Methods
➢ We can access the methods of parent class using the super keyword.

public virtual class Person { public class Student extends Person{


public String name; String studentId;
public Integer age; public Student(String studentId,
public Person(String name, Integer String name, Integer age){
age){ super(name, age);
this.name = name; this.studentId = studentId;
this.age = age; }
} public void
public void displayPersonInfo(){ displayStudentInfo(){
System.debug('The name is super.displayPersonInfo();
'+this.name+' and the age is System.debug('Student Id is:
'+this.age); '+this.studentId);
} }
} }
Pass by Value vs Pass by Reference

➢ In Pass by value a copy of variable is passed.


➢ However, in Pass by reference, the actual variable itself is passed to the method.
Pass by Value vs Pass by Reference
public void mainReferenceMethod()
public class Demo3 {
{
public void mainValueMethod()
Account a = new Account();
{
a.Name = 'Test Account';
String websiteUrl = 'www.apexhours.com';
a.Website = 'www.apexhours.com';
System.debug('Before value call ' + websiteUrl);
System.debug('Before reference call ' + a);
passByValueCall(websiteUrl); //Pass by Value
passByRefCall(a); //Pass by Reference Call
System.debug('After value call ' + websiteUrl);
System.debug('After reference call ' + a);
}
}
private void passByRefCall(Account a)
private void passByValueCall(String websiteUrlValue)
{
{
a.Website = 'www.salesforce.com';
websiteUrlValue = 'www.salesforce.com';
}
}
}
Inner Apex Class or Wrapper Class

➢ Class within class

➢ When a class is supposed to used by only one class.

➢ Instance of inner class can not be created without creating instance of outer
class.
Inner Apex Class or Wrapper Class
public class Company {
public String companyName;
public String ceo;
public Integer employeeCount;
public Long revenue;

// List of all customers


private List<Client> customers = new List<Client>();
// add new customer
public void addNewCustomer(String name, String website, String email, Long phone) {
Client customer = new Client(name, website, email, phone);
customers.add(customer);
}
Inner Apex Class or Wrapper Class
// print the list of all customers
public void getAllCustomers(){
for(Client customer : customers){
System.debug('Customer Name: '+customer.clientName+', Website: '+customer.website+', Phone:
'+customer.phone+', Email: '+customer.email);
} }
// private inner class to store customer information
private class Client {
public String clientName;
public String website;
public String email;
public Long phone;
Client (String clientName, String website, String email, Long phone){
this.clientName = clientName;
this.website = website;
this.email = email;
this.phone = phone; } } }
Inner Apex Class or Wrapper Class
//at Dev-console
Company lnx = new Company();
lnx.companyName = 'Learnowx';
lnx.ceo = 'Ajay Dubedi';
lnx.employeeCount = 1200;
lnx.revenue = 1000000;

lnx.addNewCustomer('Cloud Analogy', 'cloudanalogy.com', 'cloudanalogy@gmail.com', 7778889990L);


lnx.addNewCustomer('Forcebolt', 'forcebolt.com', 'forcebolt@gmail.com', 7778889990L);
lnx.addNewCustomer(Propelguru, Propelguru.com', Propelguru@gmail.com', 6668889990L);

lnx.getAllCustomers();
Annotations
➢ An apex annotation modifies the way that a class/method or variable is used.
➢ Annotations are defined with an initial @ symbol, followed by the appropriate
keyword.
global class MyClass {
@deprecated
@future //Used for Asynchronous Apex
public void game-2010()
Public static void myMethod(String a)
{
{
System.debug(‘this is older version’);
//long-running Apex code
}
}
}

Refer Link: Annotations | Apex Developer Guide


Exceptions

➢ An exception denotes an error or event that disrupts the normal flow of code

execution.

➢ Exception disrupts the normal flow of the application hence to keep the

application running we use exception handling.


Exception Handling
➢ Exception handling is the process of responding to exceptions that appear in
the code during its runtime so that the normal flow of the application can be
maintained.

try, catch and finally statement


➢ Try block contains the code that may throw exception.
➢ Catch block contains the exception handler for exceptions in the try block.
➢ The finally block contains the critical code that will execute regardless of
whether the exception has occurred or not.
➢ Both catch and finally are optional, but you must use one of them.
Exception Handling

throw statements can be used to generate exceptions, while try, catch,


and finally can be used to gracefully recover from an exception.
Exception Handling
Example
try{
Double result = 10/0;
System.debug('Result: '+result);
} catch(MathException e){
System.debug('Caught math exception ');
} finally {
System.debug('finally called ');
}
Exception Handling
Example
try{
Account accRec = new Account();
insert accRec;
System.debug('Empty try block ');
} catch(DmlException e){
System.debug('Caught DML exception ');
} finally {
System.debug('finally called ');
}
Exception Handling

Built-In Exceptions

Exception Class and Built-In Exceptions | Apex Developer Guide


Exception Handling
Generic Exception
Since there are many built-in exceptions, if you do not want to put catch block for
every exception, you can make a catch block for generic exception.

try{
Account accRec = new Account();
insert accRec;
System.debug('Empty try block ');
} catch(Exception e){
System.debug('Caught generic exception ');
} finally {
System.debug('finally called ');
}
Exception Methods

Name Return Type Description


getCause Exception Returns the cause of the exception as an exception object.
Returns the line number from where the exception was
getLineNumber Integer
thrown.

getMessage String Returns the error message that displays for the user.

getStackTraceString String Returns the stack trace as a string.


Returns the type of exception, such as DmlException,
getTypeName String
ListException, MathException, and so on.

setMessage Void Sets the error message that displays for the user.
Exception Methods
Example: try{
Account accRec = new Account();
insert accRec;
System.debug('Empty try block ');
} catch(Exception e){
system.debug('Cause '+e.getCause());
system.debug('Message '+e.getMessage());
system.debug('Line Number '+e.getLineNumber());
system.debug('Stack Trace '+e.getStackTraceString ());
} finally {
System.debug('finally called ');
}
Create Custom Exception
➢ We can create custom exception class by Extending the Exception class.
➢ Custom exception class should end with word Exception.
public class NewException extends Exception {
}
public class Person {
public void canVote(Integer age){
try{
if(age<18){
throw new NewException();
}else{
System.debug('You can vote');
}
}catch(NewException e){
System.debug(e.getTypeName());
}finally{
System.debug('This is finally block'); }
}
}
Assertion Methods
➢ Use Assert method to prove that your code is working fine.

assert(condition, msg)
➢ Asserts that the specified condition is true.
➢ If it is not, a fatal error is returned that causes code execution to halt.
assertEquals(expected, actual, msg)
➢ Asserts that the first two arguments are the same.
➢ If they are not, a fatal error is returned that causes code execution to halt.lt.

assertNotEquals(expected, actual, msg)


➢ Asserts that the first two arguments are different.
➢ If they are the same, a fatal error is returned that causes code execution to halt.
Apex Unit Test
Why Test

➢ Ensure code is working.

➢ 75% code coverage is required for deployment in production.

➢ Catch bugs Early

➢ Prevent Regression.
What to Test in Apex
➢ Single action

○ Test to verify that a single record produces the correct, expected result.
➢ Bulk actions
○ Any Apex code, whether a trigger, a class or an extension, may be invoked for 1 to 200 records. You must test
not only the single record case, but the bulk cases as well.
➢ Positive behavior
○ Test to verify that the expected behavior occurs through every expected permutation, that is, that the user
filled out everything correctly and did not go past the limits.
➢ Negative behavior
○ There are likely limits to your applications, such as not being able to add a future date, not being able to
specify a negative amount, and so on. You must test for the negative case and verify that the error messages
are correctly produced as well as for the positive, within the limits cases.
➢ Restricted user
○ Test whether a user with restricted access to the sObjects used in your code sees the expected behavior.
That is, whether they can run the code or receive error messages.
Apex Unit Tests
➢ To facilitate the development of robust, error-free code, Apex supports the
creation and execution of unit tests.
➢ Unit tests are class methods that verify whether a particular piece of code is
working properly
➢ Unit test methods take no arguments, commit no data to the database, and
send no emails.
➢ Such methods are flagged with the @isTest annotation in the method
definition.
➢ Unit test methods must be defined in test classes, that is, classes annotated
with @isTest.
Test Class Syntax
@isTest
@isTest
public class MyClass
public class MyClass
{
{
static testMethod void myTest()
@isTest
{
public static void myTest()
//code
{
}
//code
}
}
}

@isTest annotation with test method is equivalent to testMethod keyword .


Testing Apex
➢ Apex provides a testing framework that allows you to write unit tests, run your tests,
check test results, and have code coverage results.
➢ Testing is the key to successful long-term development and is a critical component of
the development process.
➢ Unit testing is done by developers.
➢ Before you can deploy your code or package it for the Salesforce AppExchange, code
coverage must be 75%. (Unit tests must cover at least 75% of your Apex code, and all of
those tests must complete successfully.)
➢ Test method can only be created within test class.
➢ A test method must be public/global, static and must not return any value.
Testing Apex
Unit test considerations

➢ Test methods can not be used to test Web service callouts. (This is the reason why
required code coverage is not 100%). Please use callout mock .

➢ You can not sent email messages from test methods.

➢ Since test methods don’t commit data created in a test, you don't have to delete test data
upon completion.

➢ System.debug statement are not counted as a part of apex code limit.

➢ Test method and test classes are not counted as a part of code limit.
Structure of a Test

➢ Create Test Data

➢ Run Code

➢ Assert Results
What is Test data
➢ Test data is the transient data that is not committed to the database and is created by
each test class to test the Apex code functionality for which it is created.

➢ Use of this transient test data makes it easy to test the functionality of other Apex
classes and triggers.

➢ This does not change the data already in the system, nor any cleanup required after
testing has been finished.

➢ Test classes can be moved to any org and executed there as they create their own data;
hence, they are org agnostic.
How to create Test Data

➢ Manually create it for each test

➢ Load data via CSV Static resource

➢ Test setup

➢ Test Factory
Testing Apex
//Make a class to be tested
public void display(){
public class Covid19{
System.debug('Number of Cases in city: '+this.NumberOfPatientInCity);
public Integer NumberOfPatientInCity = 0;
System.debug('Number of Cases in Country:
public static Integer NumberOfPatientInCountry = 0;
'+NumberOfPatientInCountry);
}
public Covid19(Integer numberOfPatient){
}
this.NumberOfPatientInCity = numberOfPatient;
//Make a test class for above class
NumberOfPatientInCountry += numberOfPatient;
@isTest
}
public class Covid19Test {
@isTest
public void incrasePatient(){
public static void incrasePatientTest(){
NumberOfPatientInCity++;
Covid19 noida = new Covid19(5);
NumberOfPatientInCountry++;
Integer num = noida.localPatient();
}
System.assertEquals(5, num, 'num does not match');
public Integer localPatient(){
}
return NumberOfPatientInCity;
}
}
@isTest

Testing Apex private class TemperatureConverterTest {


@isTest static void testWarmTemp() {
Decimal celsius = TemperatureConverter.FahrenheitToCelsius(70);
Unit Test Example: Test the TemperatureConverter Class
System.assertEquals(21.11,celsius);
}

public class TemperatureConverter @isTest static void testFreezingPoint() {


{ Decimal celsius = TemperatureConverter.FahrenheitToCelsius(32);
public static Decimal FahrenheitToCelsius(Decimal fh) System.assertEquals(0,celsius);
{
Decimal cs = (fh - 32) * 5/9; }
return cs.setScale(2); @isTest static void testBoilingPoint() {
}
Decimal celsius = TemperatureConverter.FahrenheitToCelsius(212);
}

System.assertEquals(100,celsius,'Boiling point temp is not expected.');


}
@isTest static void testNegativeTemp() {
Decimal celsius = TemperatureConverter.FahrenheitToCelsius(-10);
System.assertEquals(-23.33,celsius);
}
}
Testing Apex @isTest
public class EventUtilityTest {
Unit Test Example: Test the EventUtility Class @isTest
private static void testEventStatusLength(){
String res = EventUtility.eventPriority('IND');
public class EventUtility { System.assertEquals(null, res);
public static String eventPriority(String eventStatus){
}
String eventPri;
if(String.isBlank(eventStatus) || eventStatus.length() > 2){ @isTest
eventPri = null; private static void testHighPri(){
}else if(eventStatus == 'CA'){
String res = EventUtility.eventPriority('CA');
eventPri = 'High';
}else{ System.assertEquals('High', res);
eventPri = 'Medium'; }
}
return eventPri; @isTest
} private static void testMediumPri(){
} String res = EventUtility.eventPriority('BU');
System.assertEquals('Medium', res);
}
}
Testing Apex
Update the account rating to hot and active status to yes if account has related contact

public class UpdateAccount { @isTest


public static void updateAccountRating(){ public class UpdateAccountTest {
@isTest
List<Account> accToBeUpdate = new List<Account>();
private static void updateAccountRatingTest(){
Set<Id> accId = new Set<Id>(); Account acc = new Account();
for(Contact con: [SELECT Id, Name, AccountId FROM acc.Name = 'Cloud Account-002';
Contact WHERE Name LIKE '%Test%' AND AccountId != null]){ acc.Rating = 'Cold';
if(!accId.contains(con.AccountId)){ acc.Active__c = 'No';
Account acc = new Account(); insert acc;
Contact con = new Contact();
acc.Id = con.AccountId;
con.LastName = 'Test Contact';
acc.Rating = 'Hot'; con.AccountId = acc.Id;
acc.Active__c = 'Yes'; insert con;
accId.add(acc.Id); UpdateAccount.updateAccountRating();
accToBeUpdate.add(acc); } } Account updateAcc = [SELECT Id, Rating, Active__c FROM Account
if(!accToBeUpdate.isEmpty()){ WHERE Id = :acc.Id];
update accToBeUpdate; System.assertEquals('Warm', updateAcc.Rating, 'Ratings are not up
to logic');
} }
System.assertEquals('Yes', updateAcc.Active__c, 'Active is not up to
} logic'); } }
Testing Apex
Create 20 new Accounts Records in salesforce with at least 5 fields filled. Write its Test class as well.

public class CreatingAccoundRecords { @isTest


public static void logicToCreateAccount(){ private class CreatingAccoundRecordsTest {
List<Account> accLst=new List<Account>();
@isTest
for(Integer i=1;i<=20;i++){
Account acc=new Account(); static void logicToCreateAccountTestMethos(){
acc.Name='Cloud Anology'+i; System.Test.startTest();
acc.AccountNumber='123456789'+i; CreatingAccoundRecords.logicToCreateAccount();
acc.Phone='1234565'+i;
System.Test.stopTest();
acc.Website='WWW.google'+i+'.com';
acc.AnnualRevenue=123+i; List<Account> accountsLst = [SELECT
accLst.add(acc); Id,Name,AccountNumber,Phone,AnnualRevenue FROM Account
}
WHERE Name Like 'Cloud Anology%'];
if(!accLst.isEmpty()){
insert accLst; System.assertEquals(20, accountsLst.size());
System.debug('Inserted records are---'+accLst); System.assertNotEquals(null, accountsLst.size());
}
}
}
}
}
Testing Apex
Unit Test Example: Create a class to insert an account and some contacts into this account. Then Write Test class for the same.

public class AccountAndContact {


public Static void createAccAndCon(){ con.Phone = '987654321'+i;
Account acc = new Account(); con.AccountId = acc.Id;
acc.Name = 'Learnowx1'; conList.add(con);
acc.Website = 'Learnowx1.com';
Insert acc; }
if(!conList.isEmpty())
List<Contact> conList = new List<Contact>(); insert conList;

for(Integer i = 1; i<=4; i++){ }


Contact con = new Contact();
con.FirstName = 'Raman';
con.LastName = 'Kumar'+i; }
Testing Apex
Unit Test Example: Create a class to insert an account and some contacts into this account. Then Write Test class for the same.

public class AccountAndContact {


public Static void createAccAndCon(){ con.Phone = '987654321'+i;
Account acc = new Account(); con.AccountId = acc.Id;
acc.Name = 'Learnowx1'; conList.add(con);
acc.Website = 'Learnowx1.com';
Insert acc; }
if(!conList.isEmpty())
List<Contact> conList = new List<Contact>(); insert conList;

for(Integer i = 1; i<=4; i++){ }


Contact con = new Contact();
con.FirstName = 'Raman';
con.LastName = 'Kumar'+i; }
Testing Triggers
Create a trigger to copy the billing address to shipping address. Write the test class to test the same trigger.

trigger AccountTrigger on Account (before insert, before public class AccountTriggerHandler {


update, before delete, after insert) {
Public static void copyBillingToShipping(List<Account> newList){
if(Trigger.isBefore){
if(Trigger.isInsert){ for(Account acc: newList){
if(acc.Copy_Billing_To_Shipping__c == true){
AccountTriggerHandler.copyBillingToShipping(Trigger.new
acc.ShippingCity = acc.BillingCity;
);
}else if(Trigger.isUpdate){ acc.ShippingCountry = acc.BillingCountry;
acc.ShippingPostalCode = acc.BillingPostalCode;
AccountTriggerHandler.copyBillingToShipping(Trigger.new
); acc.ShippingState = acc.BillingState;
} acc.ShippingStreet = acc.BillingStreet;
} }
}
}
}
}
Testing Triggers
Create a trigger to copy the billing address to shipping address. Write the test class to test the same trigger.

@isTest @isTest
public class AccountTriggerHandlerTest { private static void copyBillingToShippingUpdateTest(){
@isTest List<Account> accList = new List<Account>();
private static void copyBillingToShippingInsertTest(){ for(Integer i=0; i<2; i++){
List<Account> accList = new List<Account>(); Account acc = new Account();
for(Integer i=0; i<2; i++){ acc.Name = 'Test acc'+ i;
Account acc = new Account(); acc.BillingCity = 'Test city'+i;
acc.Name = 'Test acc'+ i; acc.BillingCountry = 'Test Country'+i;
acc.BillingCity = 'Test city'+i; acc.BillingState = 'Test State'+i;
acc.BillingCountry = 'Test Country'+i; acc.BillingPostalCode = '201310';
acc.BillingState = 'Test State'+i; acc.BillingStreet = 'Test street'+i;
acc.BillingPostalCode = '201310'; accList.add(acc); }
acc.BillingStreet = 'Test street'+i; Test.startTest();
acc.Copy_Billing_To_Shipping__c = true; insert accList;
accList.add(acc); } for(Integer i=0; i<2; i++){
Test.startTest(); accList[i].Copy_Billing_To_Shipping__c = true; }
insert accList; update accList;
Test.stopTest(); Test.stopTest();
Account acc = [SELECT Id, ShippingCity FROM Account Account acc = [SELECT Id, ShippingCity FROM Account WHERE Id =
WHERE Id = :accList[0].Id]; :accList[0].Id];
System.assertEquals(accList[0].BillingCity, System.assertEquals(accList[0].BillingCity, acc.ShippingCity);
acc.ShippingCity); } }}
@TestVisible Annotation
Use the @TestVisible annotation to allow test methods to access private or protected members of another class outside
the test class

public class TestVisibleExample { @isTest


private class TestVisibleExampleTest {
// Private member variable @isTest
@TestVisible private static Integer recordNumber = 1; static void test1() {
// Access private variable annotated with TestVisible
// Private method Integer i = TestVisibleExample.recordNumber;
@TestVisible private static void updateRecord(String System.assertEquals(1, i);
name) {
// Do something // Access private method annotated with TestVisible
} TestVisibleExample.updateRecord('RecordName');
} // Perform some verification
}
}
@testSetup Annotation
➢ Use test setup methods (methods that are annotated with @testSetup) to create test
records once and then access them in every test method in the test class.
➢ Test setup methods can be time-saving when you need to create reference or
prerequisite data for all test methods, or a common set of records that all test
methods operate on.
➢ Test setup methods are defined in a test class, take no arguments, and return no
value. The following is the syntax of a test setup method.
Syntax

@testSetup static void methodName() {

}
@testSetup Annotation
In setup method we are creating the data and in method1 we are changing the data. But when we are asserting the data in
method2 then it is not changed.

@isTest @isTest
public class TestSetupApex { private static void method1(){
//The data that will be created in this method can not Account acc1 = [SELECT Id,Name, Phone FROM Account
be changed by other methods WHERE Name='Test0'];
@testSetup acc1.Phone = '987675777';
private static void setup(){ update acc1;
List<Account> accList = new List<Account>(); Account acc2 = [SELECT Id,Name, Phone FROM Account
for(Integer i=0; i<2; i++){ WHERE Name='Test1'];
Account acc = new Account(); delete acc2;
acc.Name = 'Test'+i; }
accList.add(acc); @isTest
} private static void method2(){
insert accList; Account acc1 = [SELECT Id,Name, Phone FROM Account
} WHERE Name='Test0'];
System.assertEquals('987675777', acc1.Phone);
}
}
@testSetup Example
Create a trigger to copy the billing address to shipping address. Write the test class to test the same trigger using @testSetup.

trigger AccountTrigger on Account (before insert, before update, before @isTest


delete, after insert) { public class AccountTriggerHandlerTest {
if(Trigger.isBefore){ @testSetup
if(Trigger.isInsert){ private static void setup(){
AccountTriggerHandler.copyBillingToShipping(Trigger.new); List<Account> accList = new List<Account>();
}else if(Trigger.isUpdate){ for(Integer i=0; i<2; i++){
AccountTriggerHandler.copyBillingToShipping(Trigger.new); Account acc = new Account();
} } acc.Name = 'Test acc'+ i;
} acc.BillingCity = 'Test city'+i;
public class AccountTriggerHandler { acc.BillingCountry = 'Test Country'+i;
Public static void copyBillingToShipping(List<Account> newList){ acc.BillingState = 'Test State'+i;
for(Account acc: newList){ acc.BillingPostalCode = '201310';
if(acc.Copy_Billing_To_Shipping__c == true){ acc.BillingStreet = 'Test street'+i;
acc.ShippingCity = acc.BillingCity;
acc.ShippingCountry = acc.BillingCountry;
acc.ShippingPostalCode = acc.BillingPostalCode;
acc.ShippingState = acc.BillingState;
acc.ShippingStreet = acc.BillingStreet;
}
} }}
@testSetup Example
Create a trigger to copy the billing address to shipping address. Write the test class to test the same trigger using @testSetup.

if(i==0){
acc.Copy_Billing_To_Shipping__c = true;
}
accList.add(acc);
}
insert accList;
}
@isTest
private static void copyBillingToShippingUpdateTest(){
Account acc = [SELECT Id, Copy_Billing_To_Shipping__c, BillingCity FROM Account WHERE Name='Test acc1'];
Test.startTest();
acc.Copy_Billing_To_Shipping__c = true;
update acc;
Test.stopTest();

Account updatedAcc = [SELECT Id, ShippingCity FROM Account WHERE Id = :acc.Id];


System.assertEquals(acc.BillingCity, updatedAcc.ShippingCity);
}
}
Test Class Example

❖ Apex Class to delete all contacts belonging to Accounts Name FIELD


having 'A' in them. Also write the test class for the same
❖ Solution
Test Class Example

❖ Test the trigger that is sending the email to the id provided in the
email field of contact while creating the contact.
❖ Solution
Test Class Methods

❖ Test.startTest()gives developers a new set of governor limits for the


act stage of their test.
❖ Test.stopTest() then allows them to return to their previous
governor limits.
❖ It also causes any asynchronous code queued up during the act
stage to execute before the assert stage.
❖ It allows developers to test @future methods to check they are
working as expected.
❖ Example
@testSetup Annotation

Example:

https://developer.salesforce.com/docs/atlas.en-us.238.0.apexcode.meta/apexcode/ape
x_testing_testsetup_using.htm?q=@testSetup%20to%20create%20test%20records%2
0once%20in%20a%20method%20%20and%20use%20in%20every%20test%20method
%20in%20the%20test%20class%20.
Test Utility Class in Apex
➢ In test utility class we can put the code that we want to use across the classes.
@testSetup Annotation

public class TestUtility {


public static List<Account> createAccountRecords(String accName, Integer
noOfAcc, Boolean isInsert){
List<Account> accList = new List<Account>();
for(Integer i=0; i<noOfAcc; i++){
Account acc = new Account();
acc.Name = accName;
accList.add(acc);
}
if(isInsert){
insert accList;
}
return accList;
}

}
@testSetup Annotation

trigger AccountTrigger on Account (before insert, before public class AccountTriggerHandler {


update, before delete, after insert) { Public static void copyBillingToShipping(List<Account>
if(Trigger.isBefore){ newList){
if(Trigger.isInsert){ for(Account acc: newList){
if(acc.Copy_Billing_To_Shipping__c == true){
AccountTriggerHandler.copyBillingToShipping(Trigger.n acc.ShippingCity = acc.BillingCity;
ew); acc.ShippingCountry = acc.BillingCountry;
}else if(Trigger.isUpdate){ acc.ShippingPostalCode = acc.BillingPostalCode;
acc.ShippingState = acc.BillingState;
AccountTriggerHandler.copyBillingToShipping(Trigger.n acc.ShippingStreet = acc.BillingStreet;
ew); }
} }
} }
} }
@testSetup Annotation
@isTest List<Account> accList =
public class AccountTriggerHandlerTest { TestUtility.createAccountRecords('Test', 4, false);
@isTest for(Integer i=0; i<4; i++){
private static void copyBillingToShippingInsertTest(){ accList[i].BillingCity = 'Test city'+i;
List<Account> accList = accList[i].BillingCountry = 'Test Country'+i;
TestUtility.createAccountRecords('Test', 4, false); accList[i].BillingState = 'Test State'+i;
for(Integer i=0; i<4; i++){ accList[i].BillingPostalCode = '201310';
accList[i].BillingCity = 'Test city'+i; accList[i].BillingStreet = 'Test street'+i; }
accList[i].BillingCountry = 'Test Country'+i; Test.startTest();
accList[i].BillingState = 'Test State'+i; insert accList;
accList[i].BillingPostalCode = '201310'; for(Integer i=0; i<2; i++){
accList[i].BillingStreet = 'Test street'+i; accList[i].Copy_Billing_To_Shipping__c = true; }
accList[i].Copy_Billing_To_Shipping__c = true; update accList;
} Test.stopTest();
Test.startTest(); Account updatedAcc = [SELECT Id, ShippingCity FROM
insert accList; Account WHERE Id = :accList[1].Id];
Test.stopTest(); System.assertEquals(accList[1].BillingCity,
} updatedAcc.ShippingCity);
@isTest }}
private static void copyBillingToShippingUpdateTest();
Apex Triggers
Apex Triggers

➢ Trigger is an Apex code that executes before or after changes(insertion,


updation, deletion or undeletion) occur to salesforce records.

➢ Triggers can be defined on standard objects, as well as custom objects.

➢ Triggers are active by default when created. Salesforce automatically fires active
triggers when the specified database events occur.
Apex Trigger
Apex trigger is a block of code that perform custom actions before or after events
to records in Salesforce, such as insertions, updates, or deletions.

Send Email

Created Create any other record

Delete any other record


Updated Update any record related/ not
related
Fire an error if record is not
Deleted
matching a criteria
Prepopulate the record that got
Undeleted inserted/ updated
Doing a callout (integration)
When to use Apex Trigger

Thumb Rule : Point and Click Possibility Check

★ For a given requirement, if possible with point and click tools


(workflow rules/ process Builder/ Flows/ Validation rules….) go
with it.

★ If not possible , then do it with apex Triggers


Apex Trigger
Trigger Events
Types of Triggers Before Insert

After Insert
Before Triggers
Before Update

After Update

After Triggers Before Delete

After Delete

After Undelete
Apex Trigger
Order of execution when inserting a record

Flow Apex Trigger Apex Trigger Process builder Flow


Workflow

Apex Apex Apex Apex Apex Apex


code for code for code for code for code for code for
inserting inserting inserting inserting inserting inserting
DB
a record a record a record a record a record a record

Before Insert
After Insert
Apex Trigger
When to Use: Before When to use :After

1. Prepopulate on the same 1. Update any other object


record 2. Any other actions (sending email, calling external
system etc.)
1. Throw an error on validating 3. Need to do some system field on Same Record which
the record initiate the insertion/ updation

Flow Apex Trigger Apex Trigger Process builder Flow


Workflow

Apex Apex Apex Apex Apex Apex


code for code for code for code for code for code for
inserting inserting inserting inserting inserting inserting
DB
a record a record a record a record a record a record
When to use Apex Trigger

Thumb Rule : Before / After Event

★ If we need to update / prepopulate any field(s) on the same


record or to fire an error validating the record then go with
Before Event (Insert / Update)

★ In any other condition , Jump to


After Event (Insert / Update)
Apex Trigger
Syntax

trigger TriggerName on ObjectName (trigger_events) {

code_block

}
Triggers

Example

trigger HelloWorldTrigger on Account (before insert)


{
System.debug('Hello World!');
}
Trigger context variables

➢ Trigger Context variables allow developers to access run-time context of


any trigger.
➢ Trigger Context variables are used to access the records that caused the
trigger to fire.
Trigger context variables
Since triggers operate on collections, we must have a way of retrieving the collection
of records currently in scope.
There are four different collections which triggers provide for this purpose.
➢ Trigger.new (list<sObject>) - a list collection of all records in this trigger
context with their new values
➢ Trigger.old (list<sObject>) - a list collection of all records in this trigger context
with their old values
➢ Trigger.newMap (map<id, sObject>) - a map collection of all records in this
trigger context with their new values and mapped to their IDs
➢ Trigger.oldMap (map<id, sObject>) - a map collection of all records in this
trigger context with their old values and mapped to their IDs
Trigger context variables
It is important to note that not every trigger has all of these collections available.
In fact, only the update trigger has all four available.
Insert triggers only have trigger.new. They do not have trigger.newmap because the
records do not have an ID to map to. Insert triggers also do not have either trigger.old
or trigger.oldMap because these are new records—there are no old values.
Delete and undelete triggers have only the old values available and therefore only
trigger.old and trigger.oldmap. Note, however, that after a deletion takes place,
trigger.oldmap becomes limited in usefulness as the IDs mapped for the records no
longer exist in the database.
The undelete trigger is also very specific and nuanced and is therefore not commonly
used by beginners.
Trigger context variables
● Trigger Context variables allow developers to access run-time context of any trigger.
● Trigger Context variables are used to access the records that caused the trigger to
fire.
Variable Usage

Returns a list of the new versions of the sObject records.


new This sObject list is only available in insert, update, and undelete triggers, and the records can only
be modified in before triggers.

A map of IDs to the new versions of the sObject records.


newMap
This map is only available in before update, after insert, after update, and after undelete triggers.

Returns a list of the old versions of the sObject records.


old
This sObject list is only available in update and delete triggers.

A map of IDs to the old versions of the sObject records.


oldMap
This map is only available in update and delete triggers.
Trigger context variables

Variable Usage

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

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

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

size The total number of records in a trigger invocation, both old and new.
Trigger context variables
Returns true if this trigger was fired due to a delete operation, from the Salesforce user interface, Apex,
isDelete
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.

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

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


Possible values of the System.TriggerOperation enum are: BEFORE_INSERT, BEFORE_UPDATE,
operationType BEFORE_DELETE,AFTER_INSERT, AFTER_UPDATE, AFTER_DELETE, and AFTER_UNDELETE. If you vary
your programming logic based on different trigger types, consider using the switch statement with
different permutations of unique trigger execution enum states.
Trigger context variables

trigger ApexTrigger1 on Account (before insert)


{
Account a = Trigger.new[0]; //This will return first record
List<Account> a = Trigger.new;
a.NumberOfEmployees = 10;
a.Type = 'Testing';
}
When to use Apex Trigger

Example 1

★ While creating an account, if user provides billing address,


write a logic populate shipping address with billing address

Which Object : Account

Which Operation : Insert

Which Event : Before Insert


When to use Apex Trigger

Example 2

★ While creating an account, if annual revenue provided by user


is less than 1000, then write a logic to throw an error to user

Which Object : Account

Which Operation : Insert

Which Event : Before Insert


When to use Apex Trigger

Example 3

★ While creating an account, Create contact with same name and


associate account and contact

Which Object : Account

Which Operation : Insert

Which Event : After Insert


When to use Apex Trigger

Example 4

★ On user updating account record, if billing address is changed,


update all its child contacts mail address field same as
account billing address

Which Object : Account

Which Operation : update

Which Event : Update after


When to use Apex Trigger

Example 5

★ Whenever user deletes an account send an confirmation email


to user

Which Object : Account

Which Operation : delete

Which Event : Before delete


When to use Apex Trigger

Example 6

★ An active account should not be deleted

Which Object : Account

Which Operation : delete

Which Event : Before delete


Trigger Best Practices
Trigger Module
Trigger Ref Blog
Apex Trigger Best Practices

Below mentioned practices must be followed while writing triggers.

➢ One Trigger for One Object

➢ Naming Convention (e.g. ContactTrigger)

➢ Create Handler Class (Do not write logic in the trigger)

It keeps trigger simple, reusable. Unit tests are much easier.

➢ No DML & SOQL in inside the loop

➢ Use custom label to activate/deactivate your trigger in Production.


public class Question1HandlerClass {
public static void answer1Handler( List<Account> accList)
Create a trigger on Account to create {
'Default' contacts (number of contacts= try{
numbers of employee) every time an account List<Contact> conlist = new List<Contact>();
for(Account acc : accList){
is created.
if(acc.NumberOfEmployees != null){
for(Integer i=0; i< acc.NumberOfEmployees;i++){
contact con = new contact();
con.AccountId = acc.Id;
trigger AccountTrigger on Account (after insert) { con.LastName = 'Employee Num. '+i;
conlist.add(con);
if(trigger.isinsert && trigger.isafter){ }
}
Question1Handler.answer1Handler(trigger.new); }
insert conlist;
} }
catch(Exception e)
} {
system.debug('Error Messege ===>
'+e.getMessage()+''+'Line Number====>'+e.getLineNumber());
}
}
}
Create trigger on Product to setup default pricebook entry in the
standard pricebook as $1.
Apex Trigger Best Practices
1. Triggers can be used to prevent DML operations from succeeding by calling
the addError() method on a record or field. When used on Trigger.new records in
insert and update triggers, and on Trigger.old records in delete triggers, the
custom error message is displayed in the application interface and logged
2. Minimize the amount of code within a trigger. To simplify testing and reuse,
triggers should delegate to Apex classes that contain the actual execution logic.
3. Prevent an infinite loop of execution of a trigger while creating triggers on
parent and child objects, or updating same objects from the after update triggers.
4. Provide a maximum of one trigger per event per object.
5. Provide bypass logic in each trigger. The bypass logic provides an easy way to
bypass (temporarily disable) the trigger.
Apex Trigger Best Practices
6. Set only a maximum of five save points in all contexts
7. Use static variables to pass data between triggers.
8. User-defined methods in a trigger cannot be declared as static
9. When delegating from a trigger to a helper Apex class, pass only
the appropriate records to the helper class for processing.
10. Has the unnecessary/commented code removed?
11. Has the trigger logic been written in an Apex class and not within
the trigger?
12. Triggers Should Include Try/Catches.
Apex Trigger Best Practices
13. Implement Check Limits in all trigger methods.

14. Implement SaveResults checks in all trigger methods.

15. Handling of Errors in "after" trigger.

16. You must write triggers to support bulk operations (i.e., you must bulkify triggers) of up to 200
records for each call.

17. Trigger class header comment should be in proper format.

18. Keep the salesforce order-of-execution of events in mind.

19. Understand when to use before-trigger and when to user after-trigger.

20. Use trigger context-variables to identify specific event and performs tasks accordingly.
21. To reduce transaction times and limit constraints, move your complex logics or non-transactional
logics to asynchronous processing Using Change Data Capture and Async Apex Triggers.
Bulk Apex Trigger
➢ The benefit of bulkifying your code is that bulkified code can process large
numbers of records efficiently and run within governor limits on the Lightning
Platform.
➢ The following trigger assumes that only one record caused the trigger to fire.
This trigger doesn’t work on a full record set when multiple records are
inserted in the same transaction.

trigger MyTriggerSingle on Account(before insert)


{
Account a = Trigger.New[0];
a.Description = 'New description';
}
Bulk Apex Trigger
➢ This example is a modified version of previous MyTrigger. It uses a for loop to
iterate over all available sObjects.

trigger MyTriggerBulk on Account(before insert)


{
for(Account a : Trigger.New)
{
a.Description = 'New description';
}
}
Bulk Apex Trigger
➢ Write Apex Trigger where If a Record, whose stage is Closed Won, is updated
or inserted in opportunity, it updates Subject and Whatid fields in Task sObject.

trigger ClosedOpportunityTrigger on Opportunity (after insert, after update)


{
List<Task> TaskList = new List<Task>();
for(Opportunity opp : Trigger.New)
{
if (opp.StageName == 'Closed Won')
{

TaskList.add(new Task(Subject = 'Follow Up Test Task', Whatid = opp.id));


}
}
if(TaskList.size()>0)
{
insert TaskList;
}
}
More Examples on Triggers
trigger LeadTrigger on Lead (before insert, before update) {
for(Lead leadRecord : Trigger.new){
if(String.isBlank(leadRecord.LeadSource))
{
leadRecord.LeadSource = 'Other';
}
// check only in update operation
if(String.isBlank(leadRecord.Industry) && Trigger.isInsert){
leadRecord.addError('The industry field cannot be blank');
}
}
System.debug('Lead trigger 1 is executing');
}
Testing Triggers

➢ Apex Trigger too need to be tested before sending it to the production


environment.

➢ Before deploying a trigger, write unit tests to perform the actions that fire the
trigger and verify expected results.
// Test class to test the trigger
Testing Triggers
@isTest

//Trigger to check if last name is INVALID public class TestRestrictContactByName {

trigger RestrictContactByName on Contact (before insert) { @isTest

//check contacts prior to insert or update for invalid data static void CreateInvalidContact(){

for (Contact c : Trigger.New) { contact con = new contact(firstName = 'John',

if(c.LastName == 'INVALIDNAME') { //invalidname is invalid LastName = 'INVALIDNAME');

c.AddError('The Last Name "'+c.LastName+'" is not allowed for DML'); Test.startTest();

} Database.SaveResult result = Database.insert(con, false);

} Test.stopTest();

} System.assert(!result.isSuccess());

}
Apex Hammer

➢ Before each major service upgrade, Salesforce runs all Apex tests on your
behalf through a process called Apex Hammer.

➢ The Hammer process runs in the current version and next release and
compares the test results.

➢ This process ensures that the behavior in your custom code hasn’t been
altered as a result of service upgrades.
Code Coverage Requirement for Deployment

➢ Before you can deploy your code or package it for the Lightning Platform
AppExchange, at least 75% of Apex code must be covered by tests, and all
those tests must pass.

➢ In addition, each trigger must have some coverage.

➢ Even though code coverage is a requirement for deployment, don’t write tests
only to meet this requirement.

➢ Make sure to test the common use cases in your app, including positive and
negative test cases, and bulk and single-record processing.
Push Notification Limits

➢ An org can send up to 20,000 iOS and 10,000 Android push notifications per
hour.

➢ Only deliverable notifications count toward this limit.

➢ For example, a notification is sent to 1,000 employees in your company, but


100 employees haven’t installed the mobile app yet. Only the notifications sent
to the 900 employees who have installed the mobile app count toward this
limit.
Bulkification
To bulkify your code means to combine repetitive tasks in Apex! It’s the only way to
get around Governor Limit

Advantages:

➢ Consume least amount of resources

➢ Less chances of hitting governor limits

➢ Reduces transaction execution time

Thumb Rule: Never write SOQL Queries and DML statements in loops.
Bulkification
Bulkification Example: Let’s analyze the governor limit for DML statements.

//Bulkification
//Without Bulkification
List<Task> taskList = new List<Task>();
for (Opportunity opp : Trigger.new) { for (Opportunity opp : Trigger.new) {
Task t = new Task(); Task t = new Task();
t.Name = 'Give your prospect a free t-shirt'; t.Name = 'Give your prospect a free t-shirt';
t.WhatId = opp.Id; t.WhatId = opp.Id;
insert t; // You'll get an error after the 150th opp! taskList.add(t);
} }
insert taskList; // Notice this is outside the loop
Apex Code Best Practises

Apex Code Best Practices


Messaging class

Messaging class contains messaging methods used when sending a single or mass E-mail.

Messaging Methods:

SingleEmailMessage Methods: Contains methods for sending single email messages.


SingleEmailMessage Methods | Apex Reference Guide | Salesforce Developers

MassEmailMessage Class: Contains methods for sending mass email.

https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_classes_email_ou
tbound_mass.htm#apex_classes_email_outbound_mass
Messaging class
Sending E-mail

Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();

String[] toAddresses = new String[] {'harsh.mishra@cloudanalogy.com'};

String subject = 'Test Message';

String body = 'This is only a test message';

mail.setToAddresses(toAddresses);

mail.setSubject(subject);

mail.setPlainTextBody(body);

Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });


Messaging class
Sending E-mail without Template
public static void sendEmailWithoutTemplate(){
List<Messaging.SingleEmailMessage> mailList= new List<Messaging.SingleEmailMessage>();

String[ ] toAddresses = new String[ ]{'harsh.mishra@cloudanalogy.com'};


Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setSubject('Test mail for Messaging class');
mail.setPlainTextBody('This is mail for demonstartion of Messaging class in Dehradun Training.');
mail.setToAddresses(toAddresses);
mailList.add(mail);
if(!mailList.isEmpty()){
Messaging.sendEmail(mailList);
}
Messaging class
Sending E-mail with Template

First create Email Template


Messaging class
Sending E-mail with Template
public static void sendEmailWithTemplate(){
List<Messaging.SingleEmailMessage> mailList= new List<Messaging.SingleEmailMessage>();
EmailTemplate emailTemp = [SELECT Id, Subject, Body
FROM EmailTemplate WHERE Name = 'DDN Training Template' ];
Contact con = [Select Id, Name FROM Contact WHERE LastName = 'Rana'];
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setTemplateId(emailTemp.Id); //Template ID and
mail.setTargetObjectId(con.Id); // Contact ID is mandatory for sending Email using Template
mailList.add(mail);
if(!mailList.isEmpty()){
Messaging.sendEmail(mailList);
}
Messaging class
SCENARIO: update the Account record phone number from a particular value to a new value and we will be using
trigger.newMap and trigger.oldMap to see the old and the new value before and after the update is done to a record.

trigger AccountMainTrigger on Account public class createContactClass {

(before update) { public void method1(List<Account>

createContactClass obj=new newList,List<Account> oldList,Map<id,Account>


newMap,Map<id,Account> oldMap){
createContactClass();
for(Account obj:newList){
if(trigger.isbefore && trigger.isupdate)
system.debug('New Value of phone from
{
newMap'+newMap.get(obj.id).phone);
}
obj.method1(trigger.new,trigger.old,trigger.ne
for(Account obj1:oldList){
wMap,trigger.oldMap); system.debug('Old Value of phone from
} oldMap'+oldMap.get(obj1.id).phone);
} }
}
}
+1-604-256-0821 @learnowx.com

A-17, Ground Floor, Sector-63,


Noida-201307

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy