-2

I am looking for an example of a test class where you cover the

 catch (DmlException e) { //Code }

also

catch (Exception e) { //Code }
1
  • There is no general solution to all such situations. Some considerations are discussed in the canonical question I linked above.
    – David Reed
    May 18, 2021 at 15:56

1 Answer 1

4

First off, let me say that chasing code coverage is generally not a great idea (nor a great way to spend your time). It's far more important that you make appropriate assertions and test a sufficient number of cases (both positive, where your input is well-formed, and negative, where your input has some specific issue). If you test enough cases, your coverage will naturally be high.

Coverage is all about setting up your test so that you force your code to execute along the path you want it to. That's no different for exceptions.

What is different for exceptions is that it can be somewhere between hard and impossible to control when they're thrown unless you specifically design your code to accomodate that in testing. A DMLException, for example, would normally require you to use SObject's .addError(), run into a known validation rule (system-based like missing a required field, or user-defined), or one or two other things.

catch(Exception e) (also called a "pokemon catch", because you're trying to catch 'em all) is generally a red flag. Before trying to cover such a catch, you should consider removing the try/catch or making the catch match a more specific exception.

If you're dead set on needing to cover a catch statement, implementing Dependency Injection (DI for short) makes this a lot easier to test. In unit tests, you're not really concerned about how something happens (such as how an exception is thrown) so much as you're concerned about the fact that something does happen.

Using DI allows you to do things like make a specific inner class in your test which is designed to throw your desired exception, and cause the code you're testing to execute that code (and throw your exception).

Instead of this

public class MyClass{
    public void doWork(){
        Account acct = new Account();

        try{
            insert acct;
        }catch(System.DMLException e){
            // code to notify someone via email that the insert failed
        }
    }
}

You could separate the responsibility of inserting the record from the responsibility of creating the record, and inject the inserter into your class (or method)

public class MyClass(){
    // Assuming you're using the Unit Of Work pattern to aggregate and run
    //   dml operations, as laid out by the fflib apex enterprise patterns
    public void doWork(fflib_UnitOfWork uow){
        Account acct = new Account();
        uow.registerDirty(acct);

        try{
            uow.commit();
        }catch(System.DMLException e){
            // code to notify someone via email that the insert failed
        }
    }
}

That dependency-injected, concern-separated example would allow you to write a test that looks something like this

@isTest
private class MyClassTest{
    private class MyUoW extends fflib_UnitOfWork{
        // We don't really care what this method does for this test where we
        //   throw an exception, just that it exists
        public override void registerDirty(SObject record){
        }

        public override void commit(){
            throw new System.DMLException();
        }
    }

    @isTest
    static void testDoWorkDMLException(){
        MyClass mc = new MyClass();

        // Injecting our special UnitOfWork implementation to guarantee we throw
        //   our desired exception
        mc.doWork(new MyUoW());

        // Now you just need to gather the results of you handling the exception, and
        //   make assertions to verify that it was handled appropriately
    }
}

Not the answer you're looking for? Browse other questions tagged .