Cover catch block in apex test

apexcode-coverageunit-test

Can you please tell me how I can cover the Catch block?

 public static Map<Id, User> getUsersMapByProfileId(Set<Id> profileIds) {
    try {
      return new Map<Id, User>([SELECT Id FROM User WHERE ProfileId IN :profileIds AND IsActive = TRUE]);
    } catch (Exception e) {
      return new Map<Id, User>();
    }
  }

and

public static List<User> getActiveUnProvisionedUsers() {
    try {
      return [SELECT Id, Name FROM User WHERE IsActive = TRUE AND Operator_ID__c = NULL ORDER BY Name];
    } catch (QueryException e) {
      return new List<User>();
    }
  }

Best Answer

You get coverage by causing lines of code to be executed in a unit test method. So to get coverage here, you would need to do something to cause an exception to be thrown (any exception in your first method, and specifically a System.QueryException in your second).

If you can't think of how your code might possibly throw an exception, then that's usually a good sign that your code should not be trying to catch exceptions.

While it is possible to cause exceptions in both of those methods (if your test wastes 100 queries before calling that code), governor limit exceptions are final (and unable to be caught). I'm of the opinion that you should remove the try/catch blocks from both of your methods. If you don't have a catch block, then there's no need to attempt to cause an exception to get coverage.

If, for some reason, you need to be able to still run this code in a situation where you have no queries remaining, the much better approach would be to check Limits.getQueries().

e.g.

public static Map<Id, User> myMethod(){
    // Get a default value ready to be returned (if needed)
    Map<Id, User> results = new Map<Id, User>();

    // Check if you have a query to spare, and execute it if you do
    if(Limits.getQueries() < 100){
        results.putAll([SELECT Id, Name FROM User]);
    }

    return results;
}

The above example is easy to get coverage for, it's testable. Though keep in mind that coverage is only a secondary objective. The primary objective in testing is to test a variety of scenarios and assert that the results of running your code are what you expect. Test enough scenarios, and your coverage will naturally be high.

For my example, you'd want to write at least two tests:

  • One to verify that you get a non-empty map returned
  • One to verify that you get an empty map returned when you are unable to run the query

I'd want to add some extra static variable into the class being tested so you can cause the query to not be executed without the need to waste 100 queries first, but the general point of my example stands.