Mastering Test Classes in Salesforce: Different Ways to Write Them

Mastering Test Classes in Salesforce: Different Ways to Write Them

Testing in Salesforce isn’t just a best practice — it’s a requirement. Apex code must have at least 75% test coverage before it can be deployed to production. But test coverage alone doesn’t guarantee quality — well-written test classes prove your logic works, prevent regressions, and simulate real business scenarios.

In this blog, we’ll explore the different ways you can write test classes in Salesforce Apex, ranging from simple unit tests to advanced callout mocks and async jobs.


🚀 Why Are Test Classes Important?

  • Deployment requirement → 75% code coverage is mandatory.

  • Validation of business logic → ensures triggers, services, and automation behave correctly.

  • Regression prevention → catch bugs before they hit production.

  • Governance → Salesforce enforces testing discipline.


🛠️ 1. Basic Unit Test

This is the simplest form of test class — create test data, run the code, assert the results.

@IsTest
private class AccountServiceTest {
@IsTest
static void testCreateAccount() {
Account acc = new Account(Name = ‘Test Account’);

Test.startTest();
insert acc;
Test.stopTest();

Account result = [SELECT Id, Name FROM Account WHERE Id = :acc.Id];
System.assertEquals(‘Test Account’, result.Name);
}
}

✅ Use this style for basic DML and service methods.


🛠️ 2. Test Data Factory (Reusable Test Data)

Instead of repeating test data creation, use a factory class.

@IsTest
public class TestDataFactory {
public static Account createAccount(String name) {
Account acc = new Account(Name = name);
insert acc;
return acc;
}
}

@IsTest
private class FactoryTest {
@IsTest
static void testWithFactory() {
Account acc = TestDataFactory.createAccount(‘Factory Account’);
System.assertNotEquals(null, acc.Id);
}
}

✅ Recommended for large projects where many tests share the same setup.


🛠️ 3. Trigger Testing

When testing triggers, create/update/delete records and let the trigger fire.

@IsTest
private class ContactTriggerTest {
@IsTest
static void testTriggerExecution() {
Contact con = new Contact(LastName = ‘Test Con’);
insert con; // Triggers before/after insert

con.FirstName = ‘Updated’;
update con; // Triggers before/after update
}
}

✅ Useful for trigger handler classes and business logic validations.


🛠️ 4. Exception & Negative Testing

Don’t just test the happy path — test failures too.

@IsTest
private class AccountServiceTest {
@IsTest
static void testException() {
try {
insert new Account(); // Missing required Name
System.assert(false, ‘Should have thrown an exception’);
} catch (DmlException e) {
System.assert(e.getMessage().contains(‘Required fields are missing’));
}
}
}

✅ Ensures your code handles bad data gracefully.


🛠️ 5. Async Tests (Future, Queueable, Batch, Schedule)

Always wrap async calls inside Test.startTest() / Test.stopTest().

Future / Queueable
@IsTest
private class AsyncTest {
@IsTest
static void testFuture() {
Test.startTest();
MyFutureClass.doAsyncStuff();
Test.stopTest(); // Executes future/queueable now
}
}

Batch Apex

@IsTest
private class BatchTest {
@IsTest
static void testBatch() {
Test.startTest();
Database.executeBatch(new MyBatchClass(), 200);
Test.stopTest();
}
}

Scheduled Apex

@IsTest
private class ScheduleTest {
@IsTest
static void testSchedule() {
Test.startTest();
String CRON = ‘0 0 0 * * ?’;
System.schedule(‘Test Job’, CRON, new MySchedulableClass());
Test.stopTest();
}
}

✅ Required for testing automation and background jobs.


🛠️ 6. Testing Callouts (HTTP Mock)

Salesforce doesn’t allow real callouts in tests. Use HttpCalloutMock.

@IsTest
global class MockHttpResponse implements HttpCalloutMock {
global HttpResponse respond(HttpRequest req) {
HttpResponse res = new HttpResponse();
res.setStatusCode(200);
res.setBody(‘{“success”:true}’);
return res;
}
}

@IsTest
private class CalloutTest {
@IsTest
static void testCallout() {
Test.setMock(HttpCalloutMock.class, new MockHttpResponse());
String result = MyCalloutClass.makeCallout();
System.assertEquals(‘success’, result);
}
}

✅ Essential for API integrations.


🛠️ 7. SOSL / SOQL Testing

 

@IsTest
private class SearchTest {
@IsTest
static void testSOSL() {
Account acc = new Account(Name = ‘SearchAccount’);
insert acc;

List<List<SObject>> results = [FIND ‘SearchAccount*’ IN ALL FIELDS RETURNING Account(Id, Name)];
System.assertEquals(1, results[0].size());
}
}

✅ Covers search-based queries in code.


🛠️ 8. End-to-End Integration Tests

Combine multiple classes/services in one scenario.

@IsTest
private class LeadToOppIntegrationTest {
@IsTest
static void testConversionFlow() {
Lead l = new Lead(LastName=’Test Lead’, Company=’TestCo’);
insert l;

MyLeadService.convertLead(l.Id);

Opportunity opp = [SELECT Id FROM Opportunity WHERE Name = ‘TestCo Opp’ LIMIT 1];
System.assertNotEquals(null, opp);
}
}

✅ Ensures different parts of the system work together.

✅ Best Practices for Test Classes

  • Use @IsTest(SeeAllData=false) (default) → don’t depend on org data

  • Use Test Data Factory for clean setup

  • Always test positive, negative, and bulk scenarios

  • Wrap async code with Test.startTest() / Test.stopTest()

  • Use System.assert() to verify business rules, not just coverage

  • Aim for 95%+ coverage with quality assertions


🎯 Final Thoughts

Test classes in Salesforce are not just a checkbox for deployment. They are your safety net against breaking business processes.

By mixing the approaches above — unit tests, factory-based tests, trigger tests, async tests, callout mocks, and integration tests — you’ll write test suites that are robust, maintainable, and trusted by your team.

Leave a Comment

Your email address will not be published. Required fields are marked *