Skip to main content

Determine What You Should Test for Apex

Learning Objectives

After completing this unit, you’ll be able to:

  • Describe the key benefits of Apex unit tests.
  • Define a class with test methods.
  • Execute all test methods in a class and inspect failures.

Apex Unit Tests

The Apex testing framework enables you to write and execute tests for your Apex classes and triggers on the Salesforce Platform. Apex unit tests ensure your Apex code is high quality and meets the requirements for deploying Apex.

The Apex testing framework makes it easy to test your Apex code. Apex code can only be written in a sandbox environment or a Developer org, not in production. Apex code can be deployed to a production org from a sandbox. App developers can also distribute Apex code to customers from their Developer orgs by uploading packages to the Salesforce Platform AppExchange. In addition to being critical for quality assurance, Apex unit tests are also requirements for deploying and distributing Apex.

Apex unit tests lead to better code as it:

  • Ensures that your Apex classes and triggers work as expected.
  • Has a suite of regression tests that can be rerun every time classes and triggers are updated to ensure that future updates you make to your app don’t break existing functionality.
  • Meets the code coverage requirements for deploying Apex to production or distributing Apex to customers via packages.
  • Delivers high-quality apps to the production org, which makes production users more productive.
  • Delivers high-quality apps to package subscribers, which increases your customers’ trust.
Note

Before each major service upgrade, Salesforce runs all Apex tests on your behalf through a process called Apex Hammer. The Hammer process runs in the current version and next release, and compares the test results.

This process ensures that the behavior in your custom code hasn’t been altered as a result of service upgrades. Issues found are triaged based on certain criteria. Salesforce strives to fix all issues found before each new release.

Maintaining the security of your data is our highest priority. We don’t view or modify any data in your org, and all testing is done in a copy that runs in a secure data center.

Code Coverage Requirement for Deployment

Before you can deploy or package your code for the Salesforce Platform AppExchange, at least 75% of Apex code must be covered by tests, and all those tests must pass. In addition, each trigger must have some coverage.

Increase Your Code Coverage

When writing tests, try to achieve the highest code coverage possible, including positive and negative test cases, and bulk and single-record processing. Don’t just aim for 75% coverage, which is the lowest coverage that the Salesforce Platform requires for deployments and packages. The more test cases that your tests cover, the higher the likelihood that your code is robust.

Sometimes, even after you write test methods for all your class methods, code coverage is not at 100%. One common cause is not covering all data values for conditional code execution. For example, some data values tend to be ignored when your class method has if statements that cause different branches to be executed based on whether the evaluated condition is met. Ensure that your test methods account for these different values.

Let’s look at an example. This example includes the class method, getTaskPriority, which contains two if statements. The main task of this method is to return a priority string value based on the given lead state. The method validates the state first and returns null if the state is invalid. If the state is CA, the method returns 'High'; otherwise, it returns 'Normal' for any other state value.

public with sharing class TaskUtil {
  public static String getTaskPriority(String leadState) {
    // Validate input
    if(String.isBlank(leadState) || leadState.length() > 2) {
      return null;
    }
    String taskPriority;
    if(leadState == 'CA') {
      taskPriority = 'High';
    } else {
      taskPriority = 'Normal';
    }
    return taskPriority;
  }
}
Note

The equality operator (==) performs case-insensitive string comparisons, so there is no need to convert the string to lowercase first. This means that passing in 'ca' or 'Ca' will satisfy the equality condition with the string literal 'CA'.

This is the test class for the getTaskPriority method. The test method simply calls getTaskPriority with one state ('NY').

@IsTest
private class TaskUtilTests {
  

  @IsTest
  static void testTaskPriorityNormal() {
    //GIVEN
    String state = 'NY';
    //WHEN
    Test.startTest();
    String priority = TaskUtil.getTaskPriority(state);
    Test.stopTest();
    //THEN
    Assert.areEqual('Normal', priority);
  }
}

After running this test, the code coverage for TaskUtil is 75%. That’s not bad, but we can do better.

The reason our code coverage is at 75% is because our test class didn’t contain a test to pass an invalid state parameter. Similarly, line 11 wasn’t covered because the test method didn’t pass 'CA' as the state.

Let’s look at two more test methods to cover those scenarios. The following shows the full test class after adding the testTaskPriorityHigh and testTaskPriorityInvalid test methods.

@IsTest
private class TaskUtilTests {
  

  @IsTest
  static void testTaskPriorityNormal() {
    //GIVEN
    String state = 'NY';
    //WHEN
    Test.startTest();
    String priority = TaskUtil.getTaskPriority(state);
    Test.stopTest();
    //THEN
    Assert.areEqual('Normal', priority);
  }
  

  @IsTest
  static void testTaskPriorityHigh() {
    //GIVEN
    String state = 'CA';
    //WHEN
    Test.startTest();
    String priority = TaskUtil.getTaskPriority(state);
    Test.stopTest();
    //THEN
    Assert.areEqual('High', priority);
  }
  

  @IsTest static void testTaskPriorityInvalid() {
    //GIVEN
    String state = 'Montana';
    //WHEN
    Test.startTest();
    String priority = TaskUtil.getTaskPriority(state);
    Test.stopTest();
    //THEN
    Assert.areEqual(null, priority);
  }
}

Rerunning the test classes shows coverage for TaskUtil is now at 100%!

Other Things to Consider

Now that you have a better understanding of why we test our code, keep the following in mind when testing your Apex code.

  • You can save up to 6 MB of Apex code in each org. Test classes annotated with @IsTest don’t count toward this limit.
  • Even though test data rolls back, no separate database is used for testing. As a result, for some sObjects that have fields with unique constraints, inserting duplicate sObject records results in an error.
  • Test methods don’t send emails.
  • Test methods can’t make callouts to external services. You can use mock callouts in tests.
  • SOSL searches performed in a test return empty results. To ensure predictable results, use Test.setFixedSearchResults()to define the records to be returned by the search.

Resources

Share your Trailhead feedback over on Salesforce Help.

We'd love to hear about your experience with Trailhead - you can now access the new feedback form anytime from the Salesforce Help site.

Learn More Continue to Share Feedback