0

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'));
        }
    }
}
7
  • check this answer out, let me know it helps or not
    – Praveen
    Jun 24, 2016 at 6:23
  • 1
    @Praveen Why am I somehow not surprised my name came up?
    – sfdcfox
    Jun 24, 2016 at 6:26
  • 1
    Because you're our #1 contributor. @sfdcfox
    – Adrian Larson
    Jun 24, 2016 at 6:27
  • @sfdcfox as Adrian Larson said,you are the #1st and also the biggest contributor too.
    – Praveen
    Jun 24, 2016 at 6:34
  • 2
    @vamshikrishna You could get 100% coverage if you removed about half of the code you've written; you've over-engineered your class, so the unit test cannot necessarily reach 100% coverage.
    – sfdcfox
    Jun 24, 2016 at 6:43

2 Answers 2

2

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);
}
1

I really prefer Separation Of Concerns to approach exception testing. In general, if you have a try/catch block, it is easiest to test in isolation.

public PageReference save()
{
    try
    {
        // dml
    }
    catch (DmlException dmx)
    {
        ApexPages.addMessages(dmx);
        return null;
    }
    return somePageReference;
}

Then it's fairly easy to manipulate your state so that you will, in fact, get a DmlException. It's trivial to just use a Lookup Field and use the wrong SObjectType.

static testMethod void testSave_Exception()
{
    MyController controller = new MyController();
    controller.someListCase = new List<Case>
    {
        new Case(OwnerId=[SELECT Id FROM Profile LIMIT 1]);
    }

    Test.startTest();
        PageReference redirect = controller.save();
    Test.stopTest();

    system.assert(ApexPages.hasMessages(ApexPages.Severity.ERROR),
        'There should be error messages');
    system.assertEquals(null, redirect,
        'Should not redirect on error');
    system.assertEquals(0, [SELECT count() FROM Case]
        'Insert operation should fail');
}

Another step you can take to increase SOC is to extract your logic on when to perform your DML Operations into a separate method that just returns the Boolean. Then you can adopt the Guard Clause strategy:

public Boolean shouldSave()
{
    return /*logic from if statement*/;
}
public PageReference save()
{
    if (!shouldSave()) return null;
    try
    {
        // dml
    }
    catch (DmlException dmx)
    {
        // addMessages
    }
    return somePageReference;
}

Testing this takes more steps, but is not necessarily more complex. Your logic looks somewhat convoluted, so I will leave that as an exercise for the OP. The skeleton of the save tests can stay pretty simple though, no matter how comples shouldSave gets.

static testMethod void testSave_ShouldNotSave() { 
    system.assert(false, 'not yet implemented'); 
}
static testMethod void testSave_HappyPath() {
    system.assert(false, 'not yet implemented'); 
}
static testMethod void testSave_Error() { 
    system.assert(false, 'not yet implemented');
}
2
  • Thank you for the advise Adrian Larson. Actually I want only one save button on my VF page which will take the comments from the end user and enters it to the case comments, make them public and closes the case. Once it is done I am closing the pop-up vf page. So when I perform dml my case object has some validations on it while closing the case and it throws me the exceptions ... I can't write dml in another method because I want to stop inserting the case comments to case if their are any validation exception Jun 24, 2016 at 6:52
  • Hi sfdcfox ,I have tried your apex class and test class. even though its covering me to 81%. So are their any chances to cover it to 100% Jul 28, 2016 at 12:00

You must log in to answer this question.

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