0

I created a custom object to store errors in my code. So I am updating some of my classes to take advantage of this object, but I am now running into issues with test coverage.

I am taking advantage of Database.SaveResult and Database.Error. The specific issue is that my tests are passing, which then leaves my chunk of code surrounding the error uncovered by tests. Here is the code:

    if(createCaseList.size()>0){
        System.debug('Inserting createCaseList: ' + createCaseList);
        Database.SaveResult[] caseDML = Database.insert(createCaseList,false);
        for(Database.SaveResult sr: caseDML){
            if(sr.isSuccess()  && !Test.isRunningTest()){
                System.debug('Successfully updated case ' + sr.getId());
            } else if(!sr.isSuccess() || Test.isRunningTest()) {
                if(Test.isRunningTest()){
                    Database.Error testError = new Database.Error();
                }
                for(Database.Error err: sr.getErrors()){                        
                    System.debug('The following error has occurred.');                    
                    System.debug(err.getStatusCode() + ': ' + err.getMessage());
                    System.debug('Case fields that affected this error: ' + err.getFields());
                    Internal_Errors__c errRec = new Internal_Errors__c(Additional_Information__c = 'The inquiry tried to create a case',
                                                                       APEX_Class__c = 'inqCreateRelRecords.createRecords',
                                                                       Fields__c = err.getStatusCode() + ': ' + err.getMessage(),
                                                                       Object__c = 'Case',
                                                                       Record_ID__c = sr.getID()
                                                                      );
                    errorList.add(errRec);
                }                    
            }
        }
    }

    if(errorList.size()>0){
        insert errorList;
    }

As you can see, I tried to create an error while testing, but it can't be constructed. Database.Error testError = new Database.Error(); gives me the error Type cannot be constructed.

I can't really think of a way that the code can fail, though. So I can't even think of a way to trip it on purpose. But even if I did that, the test would fail altogether, though, would it not?

1

There are lots of ways for an insert to fail. You can fail a validation rule or a lookup field filter. You can violate a uniqueness constraint on a field. You can have an error added to the record or an exception thrown in a trigger. Etc. Etc.

In some situations, you can tailor your testing data and the input you pass to the code under test to generate such an error. If that's possible here, you can do so to properly document the behavior of your error handler and, as a side effect, obtain code coverage.

In others, it's very difficult or impossible to do so. The questions at that point are more or less threefold:

  • Is the error handler "real", that is, is it handling a genuinely possible error condition in a way that's better than just letting the exception get raised? The answer here appears to be "yes".
  • Can the code be refactored to be more modular and allow greater access for the unit test to inject data to produce the error condition, or can dependency injection make this possible? The answer to that here appears to be "maybe", and I'd suggest following this line of inquiry. (n.b. that you can create Database.Error via JSON deserialization, but it won't necessarily help you here).
  • Do we need to cover the error handler? If your code coverage for the rest of your code is complete, your error handler is minimal, and the effort required to cover it is very high, you may not wish to cover it at all. Because you're inserting logs here, I see why you feel an impetus to test it effectively.
| improve this answer | |
  • Thank you for your comment. I ended up on a call with a friend of mine who helped me find a pretty simple solution, which I will post as the solution. We really thought about just letting it sit, since I was at 72% coverage. But we decided to create some simple failure scenarios that will always happen on test. – Chance Nov 1 '18 at 15:43
0

The solution ended up being very simple. We created failures that we explicitly designed. I thought the test class would fail overall if we failed an insert failure, but I was incorrect. Here is the code that helped get coverage:

if(Test.isRunningTest()){
        createTaskList.add(new Task(OwnerId='00530000000hlkl'));
        createCaseList.add(new Case(OwnerId='00530000000hlkl'));
        createOpportunityList.add(new Opportunity(OwnerId='00530000000hlkl'));
    }

We simply added an owner ID that was not real.

| improve this answer | |
  • 1
    Yep, when you use Database.insert() with allOrNone=false, you don't get a DmlException. That's what gives you the ability to inspect those results. – David Reed Nov 1 '18 at 16:09

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.