-1

I have below batch class which having finish method

global void finish(Database.BatchableContext batchableContext){

    Savepoint sp = Database.setSavepoint();
    try{
        if(ErrorCount > 0){
            Util.logsDetect(errorExeption,auditLog);
        }
        else{
        //performing specific actions
        }
    }
    // Logging error in case of any exception
    catch(Exception e){
        Database.rollback(sp);
        Util.logsDetect(e,auditLog);
    }
}

Its getting cover Try block but not able to cover Catch block.Please suggest How I can proceed to cover Catch block

@IsTest
public class BatchClassTest{
  @IsTest
 static void Method1(){
  Test.startTest();      
  BatchClass B1 = new BatchClass();
  Database.executebatch(profileBatch, 2);      
  Test.stopTest();
}}
  • Do you mind sharing your test class here? – Mahmood May 28 '18 at 7:43
  • Remove testsetup from Method1 and add isTest – ManishG May 28 '18 at 8:30
  • That is correct.I made changes ,but how to cover catch block here – tarun May 28 '18 at 8:45
2

The simple answer here is that you need to cause an exception to be thrown.

The golden rule of unit testing is you only gain coverage for code that is executed as part of a test method. No exception means that you don't execute your catch block.

Why try to handle exceptions here?

If you aren't sure how to cause an exception to be thrown in this particular case, then that may be a sign that you shouldn't be attempting to handle exceptions. Part of the purpose of unit tests, after all, is to serve as a way to notify people when changes that they're trying to make will break existing functionality. If your batch apex works fine right now, the first sign of trouble in the future should be a failing test.

To me, it looks like your biggest concern here might be changes to validation, workflow, or process builder. One of the best practices for testing is to have a utility class to build instances of SObjects for your tests that satisfy all of your validation rules. Keeping the generic test data setup in a single location makes it easier to adapt to changes to validation rules (just modify the code in a single, well-known class).

If I haven't dissuaded you

There is a simple way to cause an exception to be thrown. Throw one yourself.

In the past, I've made use of @testVisible private static Boolean forceException = false;

The private modifier ensures that nobody can inadvertently cause exceptions in normal use. The @testVisibleannotation ensures that you can control this value from a unit test.

The last piece of the puzzle is to include something like the following inside your try block

if(BatchClass.forceException){
    throw new System.DmlException('test exception');
}

With that, you have an exceedingly simple way to guarantee that an exception is thrown, when you want it to be thrown (and only when you want it to be thrown).

You're not done yet

Remember that the main purpose of unit tests is not simple coverage, but rather to verify that your code produces the expected output using assertions. Coverage is a side-effect of running tests (and happens to be the only thing Salesforce can use as a metric to enforce some baseline code quality).

Without assertions, you're simply testing to see that your code doesn't explode when run. While that is a good thing (code not exploding, that is), what would happen if your code ended up deleting some records that shouldn't be deleted?

As is, your test would not warn you that this happened. How long would it take for you (or someone) to realize that records had been deleted? Would someone realize this before the records would be removed from the recycle bin? Do you take snapshots of your Salesforce data?

If your code adds, removes, or modifies SObjects, or if it returns a value, or if it modifies the state of a class, it is a very good idea to make assertions to verify that those things have, in fact, happened.

  • N.B. ApexMocks provides an alternative for exception throwing wherein the catch block doesn't need to be "configured" with code to coerce the exception throw. That said, using ApexMocks in batch finish() methods is tricky as you have to delegate the finish's logic to a class with instance methods that can be mocked to throw exceptions. – cropredy May 28 '18 at 22:47
0

You can cover catch block by throwing custom exception, create class which extends exception e.g.

public class MyException extends Exception {}

after creating class throw which is type of MyException using Test.isRunningTest() e.g.

    Savepoint sp = Database.setSavepoint();
    try{
        if(ErrorCount > 0){
            Util.logsDetect(errorExeption,auditLog);
        }
        else{
        //performing specific actions
        }
        if(Test.isRunningTest()){
            throw new MyException();
        }
    }
    // Logging error in case of any exception
    catch(Exception e){
        Database.rollback(sp);
        Util.logsDetect(e,auditLog);
    }

use following link to know more about custom exceptions Create Custom Exception

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.