How to Fix Code Coverage Issues in Salesforce

Code coverage is a crucial metric in Salesforce that ensures Apex’s code is well-tested and functions as expected. Salesforce mandates at least 75% code coverage for deployment to production. If code coverage falls below this threshold, deployments can fail, causing delays and bottlenecks. In this blog, we will explore common reasons for code coverage issues and provide effective strategies to fix them.
Table of Contents
What is Code Coverage in Salesforce
Code coverage in Salesforce is calculated based on the number of lines of Apex code that are executed during test runs. This metric helps identify untested code paths, reducing the risk of runtime errors. The key aspects of Salesforce code coverage include:
- Minimum 75% Coverage: At least 75% of all Apex classes must be covered by test methods before deployment.
- Test Classes: Apex test classes simulate real-world scenarios and validate business logic.
- Governor Limits: Salesforce imposes governor limits on execution time, heap size, and database queries to ensure efficient code execution.
Common Reasons for Low Code Coverage in Salesforce
Code coverage is a critical metric in Salesforce development, ensuring that Apex code is thoroughly tested before deployment. However, low code coverage can lead to deployment failures and poor application performance. Below are the common reasons for low code coverage and how to address them effectively.
1. Untested Code Blocks
Apex methods or logic branches that are not executed in test cases result in low code coverage. This often happens when conditional statements, error-handling scenarios, or alternative code paths are not included in the test scripts. Ensuring all logical flows are tested helps improve overall coverage.
2. Hardcoded Data in Tests
Using hardcoded record IDs instead of dynamically created test data can lead to test failures when running in different environments. Since Salesforce assigns unique IDs per environment, hardcoded values may become invalid, causing certain test cases to fail or be skipped, ultimately affecting coverage.
3. Lack of Test Data
Test classes that do not generate sufficient test data may leave parts of the code unexecuted. For example, if a trigger or method relies on records that are missing during test execution, the associated logic will not be tested. Creating necessary test data within test classes ensures full execution.
4. Inefficient Test Methods
Poorly structured test methods may fail to execute relevant parts of the code. Tests should be designed to cover multiple scenarios, including positive and negative cases, bulk operations, and edge cases. Writing meaningful and comprehensive test methods improves coverage.
5. Excessive Use of DML Operations
Salesforce enforces strict governor limits, and excessive use of DML (Data Manipulation Language) operations in test methods can cause test failures. This results in incomplete test execution, leaving some code untested. Optimizing test classes by reducing unnecessary DML operations can prevent such failures.
6. Skipped or Ignored Test Methods
If test methods are not marked with the @isTest
annotation, they will be ignored during test execution, reducing overall code coverage. Additionally, methods placed inside non-test classes without proper annotations may also be skipped. Always mark test methods correctly to ensure execution.
Steps to Fix Code Coverage Issues in Salesforce
To improve code coverage in Salesforce, follow these strategies:
1. Identify Low Coverage Classes
Before fixing code coverage issues, identify the classes with low coverage using the Developer Console:
- Navigate to Setup > Apex Test Execution
- Run all test classes
- Check the Code Coverage Report to identify underperforming classes
2. Write Comprehensive Test Classes
To improve code coverage, ensure that your test classes:
- Cover all logic branches (if-else conditions, loops, try-catch blocks)
- Include positive, negative, and edge-case scenarios
- Validate expected behavior using assertions (
System.assertEquals
andSystem.assertNotEquals
)
Example of a Proper Test Class
@isTest
public class AccountTest {
@isTest
static void testCreateAccount() {
// Create test data
Account acc = new Account(Name=’Test Account’);
insert acc;
// Query inserted record
Account insertedAcc = [SELECT Id, Name FROM Account WHERE Id = :acc.Id];
// Assertions
System.assertNotEquals(null, insertedAcc);
System.assertEquals('Test Account', insertedAcc.Name);
}
}
3. Ensure Proper Test Data Creation
Test methods should create their own test data instead of relying on existing records. Use the @testSetup
method to generate reusable test data:
@isTest
public class AccountTest {
@testSetup
static void setup() {
Account acc = new Account(Name=’Setup Account’);
insert acc;
}
@isTest
static void testAccountRetrieval() {
Account acc = [SELECT Id FROM Account LIMIT 1];
System.assertNotEquals(null, acc.Id);
}
}
4. Use Test.startTest() and Test.stopTest()
Salesforce imposes governor limits during test execution. Using Test.startTest()
and Test.stopTest()
resets limits and allows proper testing:
@isTest
public class BatchTest {
@isTest
static void testBatchExecution() {
Test.startTest();
MyBatchClass batch = new MyBatchClass();
Database.executeBatch(batch);
Test.stopTest();
}
}
5. Mock Callouts and External Integrations
Code coverage can drop if your code depends on external callouts. Use HttpCalloutMock
to simulate responses:
@isTest
private class MockHttpResponseGenerator implements HttpCalloutMock {
public HTTPResponse respond(HTTPRequest req) {
HttpResponse res = new HttpResponse();
res.setStatusCode(200);
res.setBody(‘{“message”:”Success”}’);
return res;
}
}
@isTest
public class CalloutTest {
@isTest
static void testCallout() {
Test.setMock(HttpCalloutMock.class, new MockHttpResponseGenerator());
MyCalloutClass.makeCallout();
}
}
6. Cover Exception Handling Code
Make sure test methods trigger exception blocks to cover all code paths:
@isTest
public class ExceptionTest {
@isTest
static void testExceptionScenario() {
try {
MyClass.methodThatThrowsException();
} catch (Exception e) {
System.assertEquals(‘Expected Exception Message’, e.getMessage());
}
}
}
7. Run Tests in Different Environments
To ensure code coverage remains high across environments, run tests in different Salesforce orgs (Sandbox, Developer Edition, Production) and monitor any discrepancies.
8. Avoid Hardcoded IDs
Using hardcoded record IDs makes tests environment-dependent. Always create fresh test records dynamically:
@isTest
public class HardcodedIdFix {
@isTest
static void testWithoutHardcodedId() {
Account acc = new Account(Name=’Dynamic Account’);
insert acc;
Account fetchedAcc = [SELECT Id FROM Account WHERE Name=’Dynamic Account’];
System.assertNotEquals(null, fetchedAcc.Id);
}
}
Best Practices for Addressing Code Coverage Issues in Salesforce
Salesforce enforces a minimum 75% code coverage requirement for deploying Apex code. To meet this requirement while ensuring high-quality code, follow these best practices:
1. Write High-Quality Unit Tests
- Use the AAA (Arrange-Act-Assert) pattern to structure tests clearly.
- Include positive, negative, and edge case scenarios to cover all possible behaviors.
- Utilize Test.startTest() and Test.stopTest() to handle governor limits effectively.
- Implement a Test Data Factory for creating reusable test data instead of hardcoding values.
2. Test Business Logic, Not Just Coverage Percentage
- Ensure that tests validate actual business requirements, not just increasing coverage numbers.
- Cover all logical paths, including
if-else
conditions and loops. - Use System.assert() statements to verify expected results.
3. Handle Private Methods with @TestVisible
- Use
@TestVisible
to expose private methods for testing, ensuring that essential logic is tested without modifying the method’s access level.
4. Mock External Dependencies
- Use HttpCalloutMock to simulate API callouts in tests.
- Avoid real API calls in tests to prevent failures due to external system dependencies.
5. Test Bulk Data Processing
- Ensure Apex classes handle bulk operations by testing with different record volumes (e.g., 1, 10, 100, 200+ records).
- Validate performance and scalability in bulk scenarios.
6. Refactor Code for Better Testability
- Follow the Single Responsibility Principle (SRP) to make code modular and easier to test.
- Avoid hardcoded values; use Custom Settings or Custom Metadata for flexibility.
7. Leverage Test Suites & Continuous Integration (CI)
- Group related tests into test suites for efficient execution.
- Use Salesforce CLI, Jenkins, or GitHub Actions to automate testing and maintain continuous integration.
8. Identify & Address Uncovered Code
- Use the Apex Test Execution page to track uncovered code.
- If a code block is not required for test coverage, wrap it with Test.isRunningTest().
Conclusion
Fixing code coverage issues in Salesforce requires a structured approach to testing. By writing comprehensive test classes, handling exceptions, using dynamic test data, and following best practices, you can ensure higher code coverage and smoother deployments. Keeping these strategies in mind will help maintain high-quality Apex code and improve system reliability.