How to Test Apex code with Field History Tracking?

How to Test Apex code with Field History Tracking?

On May 6, 2025, Posted by , In Apex,Salesforce Technical Questions, By ,,, , With Comments Off on How to Test Apex code with Field History Tracking?

Question

In Salesforce, testing Apex code that relies on field history tracking can be challenging because field history records are not automatically created during tests. This issue arises when the code queries history records, such as those for custom objects. Although the code works in production, the tests fail because no history records are available by default in the test context.

Answer

Testing Apex code that relies on field history tracking can be tricky, especially because history records are not automatically created during unit tests. However, there are ways to simulate history records and test your code accordingly.

One approach is to use Test.loadData() to load history data from a static resource, such as a CSV file, which contains mock history records. This allows you to simulate the field history tracking behavior for custom objects. You can then inject these records into your test methods.

Here’s an example of how to load and test history records:
Example Test Method:

@isTest
static void testLoadHistory() {
    List<Circuit__History> cs = Test.loadData(Circuit__History.SObjectType, 'TestCircuitHistoryData');
    system.debug(cs);  // This prints the loaded history records for inspection
}

In this example:

  • Test.loadData(Circuit__History.SObjectType, 'TestCircuitHistoryData') loads history records for a custom object Circuit__c from a static CSV file named TestCircuitHistoryData.
  • system.debug(cs) prints the loaded records to the debug log, so you can inspect the data.

See also: Salesforce Apex Interview Questions

Refactoring Your Apex Code for Testing:

If your original Apex code queries for field history data, you will need to refactor it slightly to allow injecting history data into the method. Here’s an example of refactoring the method to accept history data as an argument:

public void operateOnHistory(List<Circuit__History> history) {
    for (Circuit__History ch : history) {
        if (ch.Field == 'Card__c' && ch.OldValue != 'trouble') {
            // Your logic here
        }
    }
}

This refactor allows you to pass in mock data (such as the history records you loaded with Test.loadData()), making your method more testable.

Complete Test Class Example:

Now, here’s how you can use Test.loadData() in a complete test class:

@isTest
private class HistoryTest {
    static List<Circuit__History> circuitHistory;

    static void setup() {
        // Load the mock history data from the static resource
        circuitHistory = Test.loadData(Circuit__History.SObjectType, 'TestCircuitHistoryData');
    }

    @isTest
    static void testLoadedHistory() {
        MyCircuitClass mcc = new MyCircuitClass();

        // Create a map of Circuit records based on the ParentId from history
        Map<Id, Circuit__c> circuitsMap = new Map<Id, Circuit__c>();
        for (Circuit__History ch : circuitHistory) {
            circuitsMap.put(ch.ParentId, new Circuit__c(Id = ch.ParentId));
        }

        mcc.circuitsMap = circuitsMap;

        test.startTest();
        mcc.operateOnHistory(circuitHistory);  // Inject the mock history data
        test.stopTest();
    }
}

Explanation of the Test Class:

  • Loading the history data: In the setup() method, Test.loadData(Circuit__History.SObjectType, 'TestCircuitHistoryData') loads the history records from the CSV file stored as a static resource.
  • Mapping circuit records: In the testLoadedHistory() method, the circuitHistory is iterated, and a map of Circuit__c records is created using the ParentId field from the history data. This map is injected into the class under test (MyCircuitClass).
  • Injecting and testing: The operateOnHistory() method of MyCircuitClass is called with the mock history records. This allows you to test the logic that depends on history data, without relying on actual field history in the org.
  • Test boundaries: test.startTest() and test.stopTest() are used to mark the start and end of the test, ensuring that performance is properly measured and the test execution is isolated.

By following this approach, you can test Apex code that depends on field history tracking without relying on real field history records in Salesforce. The key is to simulate the history records using static resources and inject them into the test code, enabling you to test your business logic with mock data.

See also: List Class in Salesforce Apex

Job-Oriented Salesforce Training with 100% Money Back Assurance

Our Salesforce Course is structured to provide a deep understanding of the Salesforce platform, equipping you with the essential skills to excel in the CRM industry. This program covers fundamental modules like Salesforce Admin, Developer, and AI, combining theoretical knowledge with hands-on practice. By engaging in real-world projects and practical assignments, you’ll develop the expertise to solve complex business challenges using Salesforce solutions. Our expert trainers ensure you gain both technical proficiency and industry insights to succeed in the Salesforce ecosystem.

Beyond technical learning, our Salesforce Training in Dallas includes personalized mentorship, certification assistance, and interview preparation to enhance your career prospects. You’ll have access to extensive study resources, real-world project experience, and dedicated support throughout the program. By the end of the course, you’ll be fully prepared for certification exams and possess the problem-solving skills that employers seek. Start your Salesforce journey with us and unlock new career opportunities—Sign up for a Free Demo today!

Comments are closed.