3

I have written some apex triggers along with some classes. The triggers are quite small because all the real work happens in the classes.

trigger MyAccountTrigger on Account (after insert, after update, before delete) {
    AccountHandler accountSync = new AccountHandler();

    if (Trigger.isInsert) {
        handler.processInserts(Trigger.new);
    }

    if (Trigger.isUpdate) {
        handler.processUpdates(Trigger.new);
    }

    if (Trigger.isDelete) {
        handler.processDeletes(Trigger.old);
    }
}

I need to write unit tests for this code.

Is it better to write true unit tests that tests only test the AccountHandler class and another that only tests the trigger while mocking the dependencies? Can you even do dependency injection inside a trigger?

Or is it better to write a test that simply creates/updates/deletes Account objects, causing the trigger to be naturally executed? That would exercise both the trigger and AccountHandler class but it's really more of an integration test rather than a unit test.

What is the standard approach for this?

3

TL;DR - Testing the trigger should give you ample coverage on your handler if the tests are written properly.


You certainly can use mocking, but it's overkill. At least where I have worked throughout my career, your handler should simply compose service calls. It doesn't tell you how to carry out any task or apply any filter, but merely which actions and filters to use and in what combination. This delegation of responsibilities is key. If your handler does nothing but compose bits of functionality which you have rigorously tested elsewhere, you have no need to test the handler outside of making sure the trigger does what it is supposed to (when it is supposed to).

Typical structure is something like:

  • Trigger
    • Calls handler methods only
    • Test all validation scenarios
    • Test selective happy path scenarios
    • Verify filters are applied
  • Handler
    • Calls service method and applies filters only
    • Covered by trigger tests
  • Service
    • Define individual actions
    • Do not co-mingle logic with filtering here
      • Act on every record passed in
    • Test every cyclomatic path for each action
  • Filters
    • Define how to take one List<SObject> and get another List<SObject> on which to act
    • Test one scenario per method (either all records returned or none)
  • Not sure what happened to that bullet list...fixed. – Adrian Larson Jan 23 at 16:36
1

In Dan Appleman's Advanced Apex book, he recommends having functional (what we often call integration) tests as well as true unit tests with a focus on functional. The need for functional tests is bigger in Salesforce since we have admins and other non-coders with their hands in the system.

I use some functional tests, but use true unit tests to verify edge cases.

P.S. You cant inject dependencies into a trigger. You could use a Service Locator to approximate it. I have a small Apex Service Locator library on github.

0

Or is it better to write a test that simply creates/updates/deletes Account objects, causing the trigger to be naturally executed?

This is the route for your Unit Test. Because your trigger will execute on every DML operation, you'll want to make sure that it works as expected whenever those DML operations are executed either from UI or API.

If you look at Get Started with Apex Unit Tests, you will find one of the benefits of Unit Testing mentioned as:

Ensuring that your Apex classes and triggers work as expected

And yes, this is still a Unit Test, because you want to make sure your Trigger performs as expected. This is not an integration test. Integration Test is a much wider topic and that you necessarily interact with different systems interacting with each other and that you perform tests around those integrations.

Even though your trigger looks small, it is still carrying out the operations as mentioned in the underlying classes. And that writing a Unit Test here will in turn cover all classes invoked from the trigger and that you don't really want to write separate Unit Test for those classes as long as operations performed in that class is invoked from trigger.

  • 1
    He's using "integration test" in the sense of a test that exercises functionality above the level of an isolable code unit, rather than cross-system functionality. I find the distinction tends to be less useful in Apex since we don't have the level of mocking support as other environments, and it's a lot harder to isolate code units. – David Reed Jan 23 at 16:24
  • And from context of this specific ask, Integration Testing doesn't seem to be appropriate terminology here and thus wanted to clarify it. – Jayant Das Jan 23 at 16:28
  • Usually I call unit test for testing individual service methods, testing triggers for me has always been an integration test. – Pranay Jaiswal Jan 27 at 21:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.