What is a Test Class?
A Test class is a set of Apex code written to validate the functionality of Salesforce components, such as classes and triggers. Salesforce requires at least 75% code coverage by tests for all Apex classes and a minimum of 1% for triggers to be deployed to production. Test classes are essential for ensuring that your code works as expected and to prevent the introduction of bugs when making changes to your Salesforce environment.
Here are some key points about test classes in Salesforce:
Test Class Structure
A test class typically contains test methods that exercise the behavior of the methods and logic in your Apex classes and triggers. These test methods replicate different scenarios to validate the correctness of your code.
Test Class Methods
Test methods are annotated with @isTest to indicate that they are test methods. Test methods can be either public or private based on their intended use and purpose within the test class. Here’s a breakdown of when to use public or private test methods:
Public Test Methods
When to Use:
-
- Invoking from Outside the Test Class: Public test methods are meant to be invoked from outside the test class, typically from other test classes. This is useful when you want to reuse a specific test scenario in multiple test classes.
-
- Data Preparation for Other Test Methods: Public test methods can prepare test data and set up the environment for other test methods within the same test class. This is especially useful if several test methods require similar setup steps.
Don’t forget to check out: The Essential Guide for Salesforce Testing
Private Test Methods
When to Use:
-
- Helper Methods: Private test methods are typically used as helper methods within the same test class. They are not meant to be invoked from outside the test class but serve to break down the test logic into smaller, more manageable parts.
-
- Avoiding External Invocation: If a method is specific to a particular test case and doesn’t need to be accessed from other test classes, it can be kept private to prevent accidental invocation and maintain encapsulation.
Test Data Isolation
Test classes should create their own test data within the test class to maintain isolation from the organization’s data. This ensures that tests run consistently and do not depend on the state of the organization’s data.
Use of System. Assert() and System.assertEquals()
Within test methods, you use assertions like System. assert() and System.assertEquals() to verify that the actual outcomes match the expected results. These assertions help you confirm that your code behaves correctly under different conditions.
Governor Limits in Test Class
Test classes are subject to the same governor limits as other Apex codes. It’s important to be aware of these limits and design your test methods to respect them. For instance, there are limits on the number of DML statements that your tests can consume.
Test.startTest() and Test.stopTest()
These methods are used to define the portion of code that is covered by a specific set of governor limits. These methods are particularly useful in unit tests, allowing us to separate the setup and execution phases of the test. Here’s what each method does:
Test.startTest()
The Test.startTest() method marks the beginning of the portion of code that is subject to a new set of governor limits. When you call Test.startTest(), Salesforce resets the governor limits for the current context. Any code executed after Test.startTest() is treated as a separate transaction, with its own set of limits. This allows you to test the bulk and governor limit aspects of your code in a controlled manner.
Use Cases:
-
- Bulk Testing: If your code performs operations on a large number of records, you can use Test.startTest() to reset limits and simulate bulk processing.
-
- Governor Limit Validation: To test that your code adheres to Salesforce’s governor limits, you can use this method to measure the exact usage within the test context.
Test.stopTest()
The Test.stopTest() method marks the end of the portion of code that is subject to the new set of governor limits established by Test.startTest(). When you call Test.stopTest(), Salesforce enforces the limits again, measuring the actual consumption of resources during the test. Any asynchronous processing triggered during the test context, such as batch jobs or future methods, will be executed immediately after Test.stopTest().
Use Case:
Validation of Asynchronous Code: If your code enqueues asynchronous jobs (e.g., batch classes, future methods), you can use Test.stopTest() to ensure that these jobs execute during the test context, allowing you to validate their behavior synchronously.
@testSetup Annotation
The @testSetup annotation allows you to create common test records that are available in all test methods within the test class. This improves test performance.
General Best Practices
-
- Keep Test Methods Independent: Each test method should be independent and self-contained. Avoid relying on the order of execution or the outcomes of other test methods within the same test class.
-
- Clear Naming Conventions: Use clear and descriptive names for both test classes and test methods. A well-named test method provides insight into its purpose, making the code more readable and understandable.
-
- Regular Maintenance: Review and update test methods as the corresponding Apex code changes. Outdated or incorrect test methods can lead to false positives or negatives, making it essential to keep them aligned with the code they test.
Now Let’s Implement this with a Practical Example
@isTest private class WelcomeEmailBatchTest { @isTest private static void testBatchProcessing() { // Create test leads List<Lead> testLeads = new List<Lead>(); for(Integer i = 0; i < 5; i++) { Lead newLead = new Lead (); newLead.FirstName="Test"; newLead.LastName="Lead " + i; newLead.Email="testlead" + i + '@example.com'; newLead.Company ='salesforce'; testLeads.add(newLead); } insert testLeads; // Start the batch job Test.startTest(); WelcomeEmailBatch welcomeBatch = new WelcomeEmailBatch(); Id batchId = Database.executeBatch(welcomeBatch, 5); Test.stopTest(); // Verify that WelcomeEmailSent__c field is updated List<Lead> updatedLeads = [SELECT Id, WelcomeEmailSent__c FROM Lead WHERE Id IN :testLeads]; if(updatedLeads.size()>0){ for (Lead lead : updatedLeads) { System.assertEquals(true, lead.WelcomeEmailSent__c); } } // Verify that the batch job has been completed AsyncApexJob batchJob = [SELECT Id, Status, NumberOfErrors FROM AsyncApexJob WHERE Id = :batchId]; System.assertEquals('Completed', batchJob.Status); System.assertEquals(0, batchJob.NumberOfErrors); } }
Check out another amazing blog here: Guide To Writing Batchable Classes In Salesforce
Conclusion
In summary, Salesforce testing is essential for ensuring the reliability of your Apex code and triggers. By structuring test classes properly, using clear naming conventions, and leveraging key tools like assertions and annotations, developers can create effective tests. Keeping tests independent, maintaining data isolation, and adhering to governor limits are crucial best practices. Mastering these techniques is vital for building robust and error-free Salesforce applications, ensuring they work as intended in any scenario.
For more information on test Classes, please check: https://amansfdc.com/create-test-class-in-apex/