We write an Apex test class in Salesforce for unit testing. However, if we write Apex without a test class, it is just unusable.
Because Salesforce won’t let your code anywhere near production unless it’s backed by tests.
Testing gives you code coverage. Here, code coverage refers to the lines of code that are covered by testing.
And many more aspects of the test class in Apex need to be discussed in detail.
This guide will help you with that and explain why Salesforce won’t let you push the trigger you just wrote.
What Are Apex Test Classes?
Code that tests your code is the simple definition of the test class in Apex. Their primary work is to verify if your business logic is behaving correctly under controlled conditions.
It runs in isolation and simulates real-world data without touching live records. This ensures reliable test results without impacting the org data.
At a platform level, Salesforce enforces test classes because:
- Apex runs in a multi-tenant environment
- Governor limits can break poorly written code
- Deployments must not introduce runtime failures
A test class acts as a safety net before your code is allowed into production. That’s why it is mandatory to have a mimimum 75% of code coverage to deploy your code in production.
Why Write Test Classes in Apex?
Salesforce enforces writing test classes in Apex, but there are legit reasons for this policy. We have mentioned some of them below:
- It makes it easy to catch bugs before users do. There is a vast difference between finding a bug in your sandbox vs when your seniors email you the screenshots of error messages.
- Documenting your test code journey is helpful when you see your code after six months. You still have the context of why you wrote that recursive trigger.
- When you change something in the account trigger, the regression testing saves you while running the test. It ensures that the new changes don’t break anything.
- Governor limits won’t surprise you because the testing will run in batches. Understanding Salesforce governor limits becomes crucial when you’re processing bulk data.
Apex Test Class Annotations
@isTest Annotation
The test classes are written under the @isTest annotation. By using this annotation, we tell Salesforce that this is test code and doesn’t count against my org limit.
Without @isTest, your test class counts toward your org’s 6MB code limit, and every kilobyte matters with a large org.
What is @isTest(SeeAllData=True) vs @testSetup?
@isTest(SeeAllData=True) Annotation
Test classes run in data isolation. It means they cannot see Accounts, Contacts, Users, or any other records that exist in production or the sandbox.
When you use @isTest(SeeAllData=True) annotation, it means that the test that runs in isolation can now access your live Salesforce org data.
@isTest(SeeAllData=true)
public class LegacyProductTest {
@isTest
static void testPriceCalculationWithRealPricebook() {
// This can query actual Pricebook2 records from your org
Pricebook2 standardPricebook = [
SELECT Id, Name, IsStandard
FROM Pricebook2
WHERE IsStandard = true
LIMIT 1
];
// Can access real Products
List<Product2> existingProducts = [
SELECT Id, Name, ProductCode
FROM Product2
WHERE IsActive = true
LIMIT 5
];
System.debug('Found real pricebook: ' + standardPricebook.Name);
System.debug('Found ' + existingProducts.size() + ' real products');
// Rest of your test logic using real org data
}
}
@testSetup Annotation
On the other hand, @testSetup is about creating reusable test data, not accessing org data.
It runs once before test methods and inserts controlled records that all test methods can use.
@isTest
public class AccountTriggerTest {
@testSetup
static void setupTestData() {
// This runs ONCE before all test methods
List<Account> accounts = new List<Account>();
for(Integer i = 0; i < 200; i++) {
accounts.add(new Account(
Name = 'Test Account ' + i,
Industry = 'Technology'
));
}
insert accounts;
}
@isTest
static void testBulkUpdate() {
// Data from @testSetup is already there
List<Account> accounts = [SELECT Id, Name FROM Account];
System.assertEquals(200, accounts.size());
// Your test logic
}
}
Comparison Table
To help you better understand the difference, see the comparison table given below.
| Aspect | SeeAllData=true | @testSetup |
| Uses existing org data | ✅ Yes | ❌ No |
| Creates controlled data | ❌ No | ✅ Yes |
| Environment independent | ❌ No | ✅ Yes |
| Repeatable tests | ❌ No | ✅ Yes |
| Recommended best practice | ❌ Rarely | ✅ Yes |
Apex Test Class in Salesforce Examples
Test Class for trigger
Here is the Trigger for which we will be writing the test class:
trigger bookTrigger on book__c (before insert) {
/**
* Webkul Software.
*
* @category Webkul
* @author Webkul
* @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com)
* @license https://store.webkul.com/license.html
*/
list<book__c> li = trigger.new;
for(book__c str : li){
str.Price__c = str.Price__c * 0.8;
}
}
Now the test class will be as follows:
@isTest
private class bookTriggerTest {
/**
* Webkul Software.
*
* @category Webkul
* @author Webkul
* @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com)
* @license https://store.webkul.com/license.html
*/
static testMethod void validateHelloWorld() {
Book__c b = new Book__c(Name='Behind the Cloud', Price__c=100);
System.debug('Price before inserting new book: ' + b.Price__c);
// Insert book
insert b;
// Retrieve the new book
b = [SELECT Price__c FROM Book__c WHERE Id =:b.Id];
System.debug('Price after trigger fired: ' + b.Price__c);
// Test that the trigger correctly updated the price
System.assertEquals(80, b.Price__c);
}
}
Test Class For Extension
Here is the Controller Extension for which we will be writing a test class:
public with sharing class contactext {
/**
* Webkul Software.
*
* @category Webkul
* @author Webkul
* @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com)
* @license https://store.webkul.com/license.html
*/
public contact con;
public contactext(ApexPages.StandardController std){
con = (contact)std.getrecord();
}
public pagereference savedata(){
try{
insert con;
apexpages.addmessage(new apexpages.Message(apexpages.severity.confirm,'Contact Saved'));
}catch(exception e){
apexpages.addMessages(e);
}
pagereference pg = page.Task02_Contactext;
pg.setredirect(true);
return pg;
}
}
Now the test class will be as follows:
@isTest
public class contactextTest
{
/**
* Webkul Software.
*
* @category Webkul
* @author Webkul
* @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com)
* @license https://store.webkul.com/license.html
*/
@isTest static void testMethodForException()//Checking Records for exception
{
Account testAccount = new Account();//Insert Account
testAccount.Name='Test Account' ;
insert testAccount;
Contact cont = new Contact();
cont.FirstName ='Test';
cont.LastName ='Test';
cont.accountid =testAccount.id;
insert cont;
ApexPages.StandardController sc = new ApexPages.StandardController(cont);
contactext contactextObj = new contactext(sc);//Instantiate the Class
try
{
contactextObj.savedata();//Call the Method
}
catch(Exception e)
{}
list<account> acc = [select id from account];//Retrive the record
integer i = acc.size();
system.assertEquals(1,i);//Test that the record is inserted
}
@isTest static void testMethod1()//Testing the insertion method
{
Account testAccount = new Account();//Insert Account
testAccount.Name='Test Account' ;
insert testAccount;
Contact cont = new Contact();
cont.FirstName ='Test';
cont.LastName ='Test';
cont.accountid =testAccount.id;
try
{
ApexPages.StandardController sc = new ApexPages.StandardController(cont);
contactext contactextObj = new contactext(sc);//Instantiate the Class
contactextObj.savedata();
}
catch(Exception ee)
{}
list<account> acc = [select id from account];//Retrive the record
integer i = acc.size();
system.assertEquals(1,i);//Test that the record is inserted
}
}
Test Class For Controller
Here is the class for which we will be writing the test:
public with sharing class retrieveAcc {
/**
* Webkul Software.
*
* @category Webkul
* @author Webkul
* @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com)
* @license https://store.webkul.com/license.html
*/
public list<account> getacc(){
list<account> li = [select Name,AccountNumber,AccountSource,ParentId from account];
if(li!=null && !li.isEmpty()){
return li;
}else{
return new list<account>();
}
}
}
Now the test class will be as follows:
@isTest
private class retriveAccTest {
/**
* Webkul Software.
*
* @category Webkul
* @author Webkul
* @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com)
* @license https://store.webkul.com/license.html
*/
@isTest static void testmeth1(){
//Insert Record for testing the If situation
account acc1 = new account(name = 'acc1', AccountSource = 'Web');
account acc2 = new account(name = 'acc2', AccountSource = 'Web');
list<account> accList = new list<account>();
accList.add(acc1);
accList.add(acc2);
insert accList;
//Test that Records are Inserted
list<account> obj1 = new retrieveAcc().getacc();
system.assertequals(obj1.size(),2);
//Delete Records For testing the Else situation
delete accList;
//Test that Records are Deleted
list<account> obj2 = new retrieveAcc().getacc();
system.assertEquals(obj2.size(),0);
}
}
How To Run a Test Class in Developer Console?
Step-1:
Open the Developer Console Window.






Final Thoughts
The Apex test class in Salesforce gives confidence, and you can deploy your code without any fear. It protects your org from changes that can negatively impact your entire platform.
You can onboard new developers without praying they don’t break everything. That’s the real value.
And remember: a test that catches a bug in development is worth a thousand “sorry” emails to users.
Support
That’s all for Implementing Test Classes In Apex Salesforce. Still have any issue raise a ticket and let us know your views to make the code better.
Be the first to comment.