How to write a unit-test / test class for trigger?

  • How do I write a unit-test / test class for a trigger?

    What are my options?

    Inline with the trigger?

    New Class?

  • Apex Trigger Code Testing

    • Writing test code to invoke Apex Trigger logic is a requirement, even if you have other tests that cover other aspects of the code called from it, such as utility or library methods in other Apex classes.
    • As such you must have at least one Apex test perform the require DML operations on the object to invoke the trigger logic, no matter how little code maybe in your trigger.
    • It is common best practice these days to keep code in your Apex Trigger to a minimum and call out to another Apex class. As such it enables you to test the code in a more detailed and more focused mannor in other tests without having to setup a full data set required to issue DML requests in such tests. It also gives rise to better factoring and encapsulation as your code base grows. This consideration is popular with the TDD methodology.
    • As has already been commented you need to place test code outside of the trigger, indeed it is not actually possible to put test code in a trigger anyway.

    The following is very basic illustration of the above, it strays a little into some best practices on layering and encapsulating logic around objects, but I think is relevant here, as its important to think about all logic.

    Apex Class

    /**
     * Class encapsulates logic relating to the Account object, 
     *   other Account related logic required by VF controllers, batch jobs etc could be placed here
     */
    public with sharing class Accounts {    
    
        public static void onBeforeInsert(List<Account> accounts) { }
        
        public static void someOtherAccountFunctionality(List<Account> accounts) { }    
    } 
    

    Apex Trigger

    trigger AccountTrigger on Account (before insert) {
    
        // Delegate the trigger work to an Apex class that encapsulates behavior relating to the Account object
        if(Trigger.isInsert)
            Accounts.onBeforeInsert(Trigger.new);
    }
    

    Test Class

    @IsTest
    private with sharing class AccountsTest {
        @IsTest
        static void testAccountTriggerViaDML()
        {
                // This example is simple, illustrates how to invoke the trigger code via DML (required), 
                //   but can become complex and detract from TDD and more granularly testing of the Accounts class
                Account testAccount = new Account( Name = 'Test Account' );
                insert testAccount;
                testAccount = [select Id, Name from Account where Id = :testAccount.Id];
                System.assertEquals(testAccount.Name, 'Test Account');  
        }
        
        @IsTest
        static void testAccountsOnInsertDirectly()
        {
                // This example is simple, but illustrates the pattern gives access to the Account class code without going via DML, 
                //   more TDD flexibility here (though must be peformed in conjunction with the above style tests as well)
                Account testAccount = new Account( Name = 'Test Account' );
                Accounts.onBeforeInsert(new List<Account> { testAccount } );
                System.assertEquals(testAccount.Name, 'Test Account');
        }
    
        @IsTest
        static void testSomeOtherAccountFunctionality()
        {
                // Test a specific method on the Accounts class (this may also be tested via the tests associated with the logic calling it
                //     however in a TDD approach these tests still have a role to test such methods in more detail)
                Account testAccount = new Account( Name = 'Test Account' );
                Accounts.testSomeOtherAccountFunctionality(new List<Account> { testAccount });
                System.assertEquals(testAccount.Name, 'Test Account');
        }
    }
    

License under CC-BY-SA with attribution


Content dated before 7/24/2021 11:53 AM