[SalesForce] how to cover the test class for apexpages.addmessage

I have written a test class that covers 86% leaving out the apexpages.addmessage () in catch block, but majorly it throws the validation exceptions on that object when I try to update a record.(Here I am updating case status to closed and I have some custom fields to be filled out while closing the case).

My test class has 2 methods. 1st method is having the case with all the fields filled this covers all the code except catch block and 2nd method without the required fields while closing the case and even though it doesn't cover my test class to full 100%

In my case I am updating the case status to closed and while closing the case I have 2 custom fields that should not be "null" 1. xyz1__c and 2.xyz2__c (Their are validation rules written on the case object and these throwing me the exceptions if these fields are null while updating the case) I am not sure how to cover the validation exception in catch block in Test class

Can someone please provide any suggestions .

Apex controller

public with sharing class OCaseComment {
    public String test2 {get;set;}
    public String test1 {get;set;}
    public string status {get;set;}
    public casecomment ca;
    public case c;
    public ID caseId;
    public pagereference save() {
        caseId = ApexPages.currentPage().getParameters().get('caseid');
        system.debug('case id entered' + caseId);
        ca = new casecomment();
        ca.ParentId = caseId;
        ca.commentbody = 'question:' + test1 + '\n' + 'solution:' + test2;
        ca.IsPublished = true;
        list<case> c = [select Status, xyz1__c, xyz2__c from case where ID =: caseId];
        list<case> cg = new list<case>();
        for (case cd : c) {
            cd.Status = 'Closed';
            cg.add(cd);
        }
        try {
            if (cg.size() > 0 && cg[0].xyz1__c != null && cg[0].xyz2__c != null) {
                insert ca;
            }
            update cg;
            status = 'saved';
            system.debug('status value' + status);
        } catch (DmlException d) {
            Apexpages.addMessage(new ApexPages.message(Apexpages.Severity.Error, d.getMessage()));
            status = 'unsaved';
        }
        return null;
    }
}

Test class

@isTest
public class TestClassOCaseComment {
    @isTest public static void withcaseid() {
        case c = new
        case (status = 'New', Origin = 'Phone', xyz1__c = 'Stats', xyz2__c = 'Issues');
        insert c;
        case ca = [select id, status, xyz2__c from
            case where status = 'New'
        ];
        Test.setCurrentPage(page.SCaseComments);
        OCaseComment cs = new OCaseComment();
        cs.Test1 = ('test1');
        cs.Test2 = ('test2');
        apexpages.currentPage().getparameters().put('caseid', ca.id);
        if (ca.id != null) {
            cs.save();
        }
        casecomment cm = [select commentbody, isPublished from casecomment where parentid =: ca.Id];
        string str = 'Question:' + cs.test1 + '\n' + 'Solution:' + cs.test2;
        system.assertEquals(str, cm.CommentBody);
        system.assert(true, cm.ispublished);
        case g = [select Status from
            case where ID = :
                ca.Id
        ];
        system.assertEquals('Closed', g.status);
    }
    @isTest static void caseWithoutproduct() {
        try {
            case c = new
            case (status = 'New', Origin = 'Phone', xyz2__c = 'Issues');
            insert c;
            pagereference pr = page.SCaseComments;
            pr.getParameters().put('caseid', c.Id);
            test.setCurrentPage(pr);
            OCaseComment cc = new OCaseComment();
            cc.save();
        } catch (Exception e) {
            System.Assert(e.getMessage().contains('FIELD_CUSTOM_VALIDATION_EXCEPTION'));
            System.Assert(e.getMessage().contains('xyz1__c'));
        }
    }
}

Best Answer

Your unit test is overly cautious, and in fact is probably too cautious for its own good. You can get 100% coverage by swapping some of your code around:

public with sharing class OCaseComment {
    public String test2 {get;set;}
    public String test1 {get;set;}
    public string status {get;set;}

    public void save() {
        Id caseId = ApexPages.currentPage().getParameters().get('caseid');
        SavePoint sp = Database.setSavePoint();
        status = 'unsaved';
        try {
            Case c = [SELECT Id FROM Case WHERE Id = :caseId FOR UPDATE];
            c.Status = 'Closed';
            insert new casecomment(ParentId = caseId, commentbody = 'question:' + test1 + '\nsolution:' + test2, IsPublished = true);
            update c;
            status = 'saved';
        } catch(Exception e) {
            Apexpages.addMessage(new ApexPages.message(Apexpages.Severity.Error, d.getMessage()));
            Database.rollback(sp);
        }
    }
}

Note that I've also added transaction safety to your class, which was notably missing.

Now, the only problem left is to fix your unit test:

@isTest static void caseWithoutproduct() {
    case c = new case (status = 'New', Origin = 'Phone', xyz2__c = 'Issues');
    insert c;
    pagereference pr = page.SCaseComments;
    pr.getParameters().put('caseid', c.Id);
    test.setCurrentPage(pr);
    OCaseComment cc = new OCaseComment();
    cc.save();
    System.assert(ApexPages.hasMessages(ApexPages.SEVERITY.ERROR));
    System.assertEquals('unsaved', cc.status);
}