Apex Unit Testing Dos and Don’ts From the Trenches

Apex is Salesforce’s programming language. It is used to create custom functionality on the Salesforce platform. To ensure that custom functionality works, Salesforce requires that 75% of the overall apex code written is covered with test code. Test code is apex code that tests the custom functionality written by a developer and doesn’t count towards the 75% of code that has to be covered.

How to Write Good Unit Tests and An Introduction to Apex Code Test Methods are good resources for how to create unit tests so that content won’t be covered here. I want to share Dos and Don’ts gained from the Apex Unit Testing trenches.

Dos

  • Isolated Data Creation Code. When writing test code, it’s common to copy and paste the same data setup code across unit tests and even test classes. This is a maintenance nightmare when your tests start numbering in the hundreds or more. To resolve this, centralize the data creation into their own classes and make them parameterized so one can supply different data as needed. While requiring more investment initially, it pays many dividends later when you reuse a lot of this logic for other tests.
  • Global Data Creation Code. When creating managed packages, it’s very common to extend and customize them for client specific functionality. With global data creation classes, the non-packaged code can easily setup various scenarios without having to re-code it. This has helped me save countless hours on various implementation projects.
  • Write Failing Unit Tests For Bugs. Once you know the reproduction steps for a bug, write a failing test for it. Once the bug is fixed, the test passes and now you have added to your regression testing suite.
  • Add Assertion Messages. In the various System.assert* methods, there is an optional message parameter that shows up for additional information when the assertion fails. While it does take a little extra time initially, it can really save time troubleshooting later when the test provides enough information that you don’t have to open up the test class or enable debug logs.
  • Test Class Naming Scheme. Test classes should have names that describe what’s being tested. For test class names, I have seen two schemes “Test<apex_class>” and “<apex_class>Test” for the naming scheme. Each one signifies that it contains the test methods for a given apex class or trigger. With the “Test<apex_class>” scheme, all the tests are grouped at the bottom of the apex class listing. With the “<apex_class>Test” scheme, the test classes are right beside the class or trigger being tested in the apex class listing. Whatever scheme you adopt, make it consistent.
  • Test Method Naming Scheme. Test methods should have names that describe what’s being tested and the expected outcome. Derek Hansen, an awesome engineer and colleague, came up with the following scheme that I really like “<method_name>_<condition>_<expected_outcome>”. For example, “insertAccount_userNotAuthorized_expectNotAuthorizedException” would test the “insertAccount” method on the class being tested for a user who doesn’t have permission to create an account and it would expect it to fail.
  • Assertion Methods. Within a given test class, its very common to assert the same condition across various test methods. Put shared assertions into their own methods and use them across the test methods. An assertion method can have one or more assertions in them and usually has more than one. This helps reduce the size of test methods and centralizes the assertion code so that changes later are only needed in one place.
  • Consider Benefit / Cost Tradeoff. Test code is an investment. While only anecdotal, I’ve found that I tend to write 1-3 lines of test code for every line of non-test code. That means that it takes at least as long to write test code for a feature as it does to code the feature.  As a result, focus your time on testing the common use cases first and then edge cases based on their frequency.

Don’ts

  • Bypass Writing Test Code. While one has to consider the benefit / cost tradeoff, that does not mean not writing test code by using “Coverage Code”, marking every class as a test class, or some other way.
  • Focusing on getting 75% code coverage being the primary metric. The unit tests are meant to confirm that the software behaves as expected so let that be your primary focus and by doing so, 75% or more of your code will more often than not naturally be covered.
  • Duplicate Code. This makes initial development fast but maintenance afterward a nightmare. This, of course, applies to any code but it seems like developers “relax” their coding best practices for test code. Please don’t forget the “refactor” step in the “Red, Green, Refactor” steps. Put differently, after copying and pasting test methods, tweaking them, getting them all to pass, refactor the code to be de-duped.
  • Put all test cases in one big test method. These are notoriously hard to troubleshoot when the test starts failing long after it was created. Create one test method per test case.

What other Dos and Don’ts do you have? Do you disagree with any listed here? Let us know in the comment below.

Happy Coding,

Luke

Salesforce Field History Tracking

One of my favorite Salesforce features is Field History Tracking. Field History Tracking allows one to track a specified set of fields’ value changes over time. The field history is tracked up to 18 months by default.

Whenever a specified field is changed, Salesforce creates a new “History” record tied to the record in question. The History record contains the following information:

  • ParentId – The Id of the Salesforce record that had its field changed.
  • Field – The API name of the field that was changed.
  • OldValue – The old value of the field before the change was made.
  • NewValue – The new value of the field after the change was made.
  • CreatedById – The Id of the user who made the change.
  • CreatedDate – The UTC datetime of when the change was made.

Setup

On Standard Objects, field history tracking is setup by going to fields –> Set Field History Tracking –> Checking the fields to track and Saving.

On Custom Objects, one has to first enable field history tracking on the Object Definition page. Next, Click the “Set Field History Tracking” button, check the fields to track, and Save.

Account Setup Example

AccountFieldHistoryTracking

Note that the “(8 of 20 selected)” text is added from the Salesforce Boostr Chrome Extension, which is highly recommended.

Account Field History Example

AccountFieldHistoryTrackingExample

Benefits

  • Eases Troubleshooting – This allows an admin or developer to see what changes have happened to a record over time. When troubleshooting, this is a godsend because it allows one to see what happened to the data over various records in a given timeframe. For example, a particular user may be incorrectly entering data so that user needs additional training and/or the system needs additional validation.
  • Auditing – Certain industries require additional auditing of data for various reasons such as complying with governmental regulations. E.g Sarbanes-Oxley or HIPAA.
  • History Records don’t count towards record counts. Typically, an enterprise Salesforce org has a limit of 1GB or 500,000 records, since each record counts as 2KB. With many fields being tracked across objects, many history records can be created.
  • History Objects are queryable through SOQL. This is helpful because there are times when a bug in software has caused numerous records to be updated with wrong value(s). One can query all the parent records with their old values and reset the invalid field(s) to their former values with a data correction apex script.

Caveats

  • Changes to fields with more than 255 characters are tracked as edited, and their old and new values are not recorded.
  • If a trigger causes a change on an object the current user doesn’t have permission to edit, that change is not tracked because field history honors the permissions of the current user.
  • Detail Objects part of a Master-Detail relationship can’t have their Field History Tracking used in Salesforce reports.
  • Other Caveats

Recommendations

  • Always enable Field History Tracking and specify the fields to track.
  • If there are 20 fields or less, track all the fields.
  • If there are more than 20 fields, choose the fields to track based on priority.
  • Know that more than 20 fields can be tracked per Object for an additional cost. Contact Salesforce for more information.
  • Know that Salesforce can retain history records for longer than 18  months if needed. Contact Salesforce for more information.

What other benefits, caveats, and recommendations do you have regarding Field History tracking?

Happy Coding,

Luke

SOQL: 50,000 Record Limit Applies With Count()

In Apex, one can query up to 50,000 records in an execution context. This applies to a regular SOQL Query where records are returned such as this:

However, it also applies to count SOQL queries, despite only one record being returned. Salesforce applies the limit because it still has to iterate over the records to determine the count.

If the count SOQL query counts more than 50,000 rows, you’ll receive an error message like this:

“System.LimitException: Too many query rows: 50001”

Workarounds

Execute SOQL Query using REST / SOAP API

The Salesforce Partner or Enterprise API allows one to execute a SOQL query against it. Since it has paging built into it using a cursor behind the scenes, it’s not subject to the 50,000 row limit. One can invoke the Query endpoint with the count SOQL query to get the true number of results.

For one-off counts, often done while troubleshooting or to determine the design approach, issue the SOQL query using Workbench or through the Developer Console. Behind the scenes, they’re using the Salesforce APIs to execute the query so they won’t run into the 50,000 row limit.

As part of a Salesforce feature, one can write Apex that invokes a Salesforce API to get the count. See my Calling Salesforce Web Services Using Apex Cookbook Recipe, for detailed instructions on how to implement that.

VisualForce ReadOnly Page

If the count SOQL query is executed from a VisualForce page and the page doesn’t do any DML, aka insert, update, or delete records, mark the page as “ReadOnly”. This allows up to 1 million records to be queried.

See Salesforce Read-Only Mode Documentation for more details.

Count the SOQL count() query as a single row query Idea

One way the Salesforce community can provide feedback is through Ideas. An idea is a request that can be upvoted or downvoted by the community and commented on. After a certain threshold, Salesforce will place the Idea under review and potentially implement it.

Please upvote the Count the SOQL count() query as a single row query Idea so that hopefully no workarounds are needed in the near future.

What other workarounds and bits of wisdom do you have? Let us know in the comments below.

Happy Coding,

Luke

TypeScript 2.0 With Anders Hejlsberg

Anders Hejlsberg on TypeScript 2 is a new 30 minute discussion video with  Anders Hejlsberg describing the upcoming new features in TypeScript 2.0. Here’s a recap of the upcoming features.

Async Await

Javascript uses callback functions to allow a developer to specify the code execute after an asynchronous function executes. This can be implemented various ways such as with an inline function or with “promises”.

In TypeScript 2.0, one can use async await to call an async function and then the code to execute after it finishes comes after it instead of having to use a callback function. It has the “sequential” code style that I prefer.

Non-Null Variables

In Javascript, every variable is  nullable which leads to lots of “guard” code to check for nulls and act appropriately. With Non-Null Variables, TypeScript allows a variable to be declared as non-nullable. This reduces the amount of code needed to check for nulls and helps prevent null reference errors.

The “null reference error” is one of most problematic errors in programming. According to Anders, it costs $1 billion dollars annually.

What other TypeScript 2.0 features are you looking forward to? How have you used TypeScript?

Happy Coding,

Luke

SOQL Query Plan & SOQL Tips

With developing on the Salesforce platform since 2011, I thought I had seen all the Salesforce tools one would need. Wrong!

The other day I came across the Query Plan tool in the Developer Console. The Query Plan tool shows the cost of Salesforce executing a given SOQL query given the database statistics known at that time.

Enabling Query Plan

Salesforce doesn’t have the Query Plan feature enabled by default. To enable it, open the Developer Console –> Help –> Preferences and then check “Enable Query Plan”.

Using Query Plan

After the Query Plan is enabled, open the Query Editor tab at the bottom, enter a SOQL query, and click the Query Plan button. This will open a modal showing the cost of the SOQL query along with helpful tips.

QueryPlan

  • Cardinality – The estimated number of records that will be returned by the query.
  • Fields – The indexed field(s) used by the Query Optimizer. If the leading operation type is Index, the fields value is Index. Otherwise, the fields value is null.
  • Leading Operation Type – The primary operation type that Salesforce will use to optimize the query.
    • Index – The query will use an index on the queried object.
    • Sharing – The query will use an index based on the sharing rules associated with the user who is executing the query. If there are sharing rules that limit which records that user can access, Salesforce can use those rules to optimize the query.
    • TableScan – The query will scan all records for the queried object.
    • Other – The query will use optimizations internal to Salesforce.
  • Cost – The cost of the query compared to the Force.com Query Optimizer’s selectivity threshold. Values above 1 mean that the query won’t be selective.
  • SObject Cardinality – The approximate record count for the queried object.

Saelsforce Query Plan How To

Indexes

Salesforce leverages indexes heavily to optimize query performance whenever possible. An index is a separate data structure that stores field values in such a way that it’s fast to search on them to identify the rows we’d like returned. The general concept is the same as a book’s index. If you want to know more about “X”, see pages 10, 50, 60, etc except in this case, it’s records instead of page numbers.

What fields are indexed?

  • Object Ids
  • Object Name – Auto Number or Text Field.
  • Custom Relationsips – Master Details and Lookups.
  • External Ids
  • Unique Fields
  • Owner Field

Not sure if a field is indexed or not? Open an object’s definition page and notice that there’s an “Indexed” column. If it’s checked, it’s indexed.

AccountIndexFields

Can non-indexed fields become indexed?

Yes but it requires submitting a Salesforce case and working with Salesforce support to add the index(es) or “Skinny Tables”.

SOQL Performance Tips

When it comes to performance, one can optimize it, in general, by lessening the amount of work that the machine has to do. Here are a few ways for SOQL. Many of these are common sense, but I’m still amazed how prevalent these are violated.

  • Select only the fields needed. Select * is generally bad because more fields need to be queried, analyzed for security permissions and visibilitiy, and brought over the network to name a few.
  • Use the limit operator to reduce how many records are returned. Showing thousands of records on a page is generally a bad practice and bad user experience. Using limit with the Offset keyword can be used to implement “paging”.
  • Ensure that a SOQL query only runs once during a given execution context. In a complex application, the same SOQL query can run multiple times in a given execution context because various parts of the application depend on the same data set. One solution to prevent this is to cache the data after it’s queried and return the result set for subequent requests.
  • Use an index in the where clause whenever possible. However, this doesn’t guarantee that it will be used. Salesforce has various rules around when an index will be used or not based on its selectivity.
    • An indexed field will not be used under the following conditions:
      • Not In (….)
      • Like with wildcards “%”
      • !=
      • Excludes for picklist values
      • Not Like
      • Comparison Operators Paired With Text Fields. Text_Field <, >, <=, >=

For a deep-dive into SOQL performance considerations, take a look at the Force.com Query Optimizer FAQ and the Query & Search Optimization Cheat Sheet.

What Query Plan information do you have to share? What SOQL Performance Tips & Resources do you have?

Happy Coding,

Luke