0

I in my Apex Class I have a catch in my update. If there is a Duplicate error I am searching the Error Message for the Id so that I can run an alternate process.
This works fine when running against real data - I recieve the error message below and I am able to find the Id (001U9000004RST9IAO)

first error: DUPLICATE_VALUE, duplicate value found: LinkedIn_InternalId__c duplicates value on record with id: 001U9000004RST9IAO

However this is not working in my test class. When I debug the Error Message it reads:

first error: DUPLICATE_VALUE, duplicate value found: <unknown> duplicates value on record with id: <unknown>: []

Is there a better way to return the duplicate Id?

try{
    update updateRec;
    status = 'OK: Account Updated';
}catch(Exception e){
    if(e.getMessage().contains('DUPLICATE_VALUE')){
            System.debug('Error Message = ' + e.getMessage());
        Pattern errorPattern = Pattern.compile('duplicates value on record with id: (\\p{Alnum}{18})');
        Matcher errorMatcher = errorPattern.matcher(e.getMessage());
        errorMatcher.find();

        mergeId = (Id)errorMatcher.group(1);
    }
}

2 Answers 2

0

You can not get the actual record ID in error messages because test methods don't have access to your org data by default, and all the insertions or updates are done in a test context. That is why you are seeing instead of the actual ID.

To test for duplicate value errors, you can use the Database.saveResult class to try to catch the errors and then process them accordingly. Here is an example:

try {
        Database.SaveResult[] saveResults = Database.update(updateRec, false);
        for (Database.SaveResult sr : saveResults) {
                if (!sr.isSuccess()) {
                        for(Database.Error err : sr.getErrors()) {
                                if (err.getStatusCode() == StatusCode.DUPLICATE_VALUE) {
                                        mergeId = sr.getId();
                                        status = 'Alternate process due to DUPLICATE_VALUE';
                                }
                        }
                }
        }
} catch(Exception e) {
        status = 'Error: ' + e.getMessage();
}

Using this the Database.update method with allOrNone set to false, which allows partial successes and returns an array of Database.SaveResult. Each SaveResult has a success flag and can contain errors if the operation fails. You can check for DUPLICATE_VALUE errors specifically and handle them as needed.

1
  • Thanks for the explanation! So even in the Database.SaveResult I am unable to capture the duplicate Id in the Error Message when running a test method. I ended up working around this by adding a Test.isRunningTest() condition and query the the Id when In Test Commented May 2 at 15:03
0

Based on Tushar's response...

You can not get the actual record ID in error messages because test methods don't have access to your org data by default, and all the insertions or updates are done in a test context

I adjusted my code to query the sample duplicate record when a Test is running...

try{
    update updateRec;
    status = 'OK: Account Updated';
}catch(Exception e){
    if(e.getMessage().contains('DUPLICATE_VALUE')){
            System.debug('Error Message = ' + e.getMessage());
        if(!Test.isRunningTest()){
            Pattern errorPattern = Pattern.compile('duplicates value on record with id: (\\p{Alnum}{18})');
            Matcher errorMatcher = errorPattern.matcher(e.getMessage());
            errorMatcher.find();
    
            mergeId = (Id)errorMatcher.group(1);
        }else{
            mergeId = [SELECT Id FROM Account WHERE Name = 'Merge'][0].Id;
        }
    }
}
1
  • Adding test.isRunningTest() in PROD code is usually a "code smell"; better to use an interface and testmethod dependency injection; here's an example for SOQL but the principles apply to your example
    – cropredy
    Commented May 2 at 17:45

You must log in to answer this question.

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