[SalesForce] test custom exception in catch block

I am trying to do a negative test and cover the catch block that uses a custom exception. Whatever I try it does not enter into my catch block?

Here is my controller:

public with sharing class InnovationDetailController {

@TestVisible private List<Id> innovationIds = new List<Id>();
@TestVisible private List<InnovationService.Innovation> innovations = new List<InnovationService.Innovation>();

public Id innovationId { get; set; }
public Id ideaId { get; set; }
public String title { get; set; }
public String description { get; set; }
public Double score { get; set; }
public String awardCategory { get; set; }
public Boolean hasVoted { get; set; }
public String username { get; set; }

public InnovationDetailController() {
    innovationIds.add(ApexPages.currentPage().getParameters().get('id'));
    innovations = InnovationService.getInnovation(innovationIds);
    innovationId = innovations[0].innovationId;
    ideaId = innovations[0].ideaId;
    title = innovations[0].title;
    description = innovations[0].description;
    score = innovations[0].score;
    awardCategory = innovations[0].awardCategory;
    hasVoted = InnovationService.hasVoted(ideaId, UserInfo.getUserId());
    username = UserInfo.getName();  
}

public PageReference vote() {
    try {
        InnovationService.vote(innovationIds);
    }
    catch(InnovationService.InnovationServiceException ex) {
        ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, ex.getMessage()));
    }
    return null;
}
}

Here is my service class:

public with sharing class InnovationService {

private static List<INN_Innovation__c> getInnovations(List<Id> innovationIds) {
    return [select Id, INN_Idea__c, INN_Idea__r.Title, INN_Idea__r.Body, INN_Idea__r.VoteTotal, INN_InnovatorsAwardCategory__c from INN_Innovation__c where Id in: innovationIds limit: Limits.getLimitQueryRows()];
}

public static List<InnovationService.Innovation> getInnovation(List<Id> innovationIds) {
    List<InnovationService.Innovation> innovations = new List<InnovationService.Innovation>();
    if(!innovationIds.isEmpty() && innovationIds.size() > 0) {
        for(INN_Innovation__c i : getInnovations(innovationIds)) {
            InnovationService.Innovation innovation = new InnovationService.Innovation();
            innovation.innovationId = i.Id;
            innovation.ideaId = i.INN_Idea__c;
            innovation.title = i.INN_Idea__r.Title;
            innovation.description = i.INN_Idea__r.Body;
            innovation.score = i.INN_Idea__r.VoteTotal;
            innovation.awardCategory = i.INN_InnovatorsAwardCategory__c;
            innovations.add(innovation);
        }
    }
    return innovations;
}

// checks whether the logged in user has already voted for a given idea
public static Boolean hasVoted(Id ideaId, Id userId) {
    boolean retval = false;
    if(ideaId != null && userId != null) {
        List<Vote> result = [Select Id From Vote where ParentId =: ideaId and CreatedById =: userId];
        if(result.size() > 0) {
            retval = true;
        }
    }
    return retval;
}

public static void vote(List<Id> innovationIds) {
    Map<Id, Vote> recordsToInsert = new Map<Id, Vote>();
    if(!innovationIds.isEmpty() && innovationIds.size() > 0) {
        for(INN_Innovation__c i : getInnovations(innovationIds)) {
            Vote v = new Vote();
            v.ParentId = i.INN_Idea__c;
            v.Type = 'Up';
            recordsToInsert.put(v.Id, v);
        }
    }
    if(!recordsToInsert.isEmpty() && recordsToInsert.size() > 0) {
        try {
            insert recordsToInsert.values();
        }   
        catch(InnovationServiceException ex) {
            throw new InnovationServiceException(ex);           
        }           
    }
}

public class InnovationServiceException extends Exception {}    

public class Innovation {
    public Id innovationId;
    public Id ideaId;
    public String title;
    public String description;
    public Double score;
    public String awardCategory;
}
}

Test Method:

static testMethod void testVoteCatchBlock() {
    initialize();

    testUser = TestDataFactory.createTestUser(true, true);
    system.assertNotEquals(null, testUser.Id);

    system.runAs(testUser) {
        PageReference pageRef = Page.InnovationDetail;
        Test.setCurrentPage(pageRef);

        ApexPages.currentPage().getParameters().put('id', testInnovation.Id);
        ctrl = new InnovationDetailController();
        system.assertEquals(false, ctrl.hasVoted);

        ctrl.innovationIds = null;

        test.startTest(); 
            ctrl.vote();
        test.stopTest();
    }

    List<Vote> result = [Select Id From Vote where ParentId =: testIdea.Id and CreatedById =: testUser.Id];
    system.assertEquals(0, ctrl.innovations.size());
    system.assertEquals(true, ApexPages.hasMessages());
}

Any help is appreciated.
Thanks.

Best Answer

You are looking to test this catch block, right?

catch(InnovationService.InnovationServiceException ex) {
    ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, ex.getMessage()));
}

And you are expecting that that exception to be thrown by this block, right?

try {
    insert recordsToInsert.values();
} catch(InnovationServiceException ex) {
    throw new InnovationServiceException(ex);           
}   

If my assumption is right, then I don't think you will ever be generating that error. insert <sobjects> will not throw your custom exception but System.DmlExeption (and other standard exceptions).

One way you can generate that error is to try to insert a Vote object without some required values not specified, catch System.DmlException and convert to InnovationServiceException, may be like this.

try {
    insert recordsToInsert.values();
} catch(System.DmlException ex) {
    throw new InnovationServiceException(ex);           
}   
Related Topic