1

I'm receiving an error during deployment from a managed apex test class - ChatterAnswersEscalationTriggerTest. My code is listed below. Need the corrected code to update the test class.

Error: System.QueryException: List has no rows for assignment to SObject Stack Trace: Class.ChatterAnswersEscalationTriggerTest.validateQuestionEscalation: line 17, column 1

Pretty sure the error has to do with this line in the test class: Case ca = [SELECT Origin, CommunityId, Subject, Description from Case where QuestionId =: q.Id];

Apex Test Class

@isTest 
private class ChatterAnswersEscalationTriggerTest2 { 
static testMethod void validateQuestionEscalation() { 
String questionTitle = 'questionTitle'; 
String questionBody = 'questionBody'; 
Community[] c = [SELECT Id from Community]; 
// We cannot create a question without a community 
if (c.size() == 0) { return; } 
String communityId = c[0].Id; 
Question q = new Question(); 
q.Title = questionTitle; 
q.Body = questionBody; 
q.CommunityId = communityId; 
insert(q); 
q.Priority = 'high'; 
update(q); 
Case ca = [SELECT Origin, CommunityId, Subject, Description from Case where QuestionId =: q.Id]; 
// Test that escaltion trigger correctly escalate the question to a case 
System.assertEquals(questionTitle, ca.Subject); 
System.assertEquals(questionBody, ca.Description); 
System.assertEquals('Chatter Answers', ca.Origin); 
System.assertEquals(communityId, ca.CommunityId); 
} 
}

Apex Trigger chatter_answers_question_escalation_to_case_trigger

trigger chatter_answers_question_escalation_to_case_trigger on Question (after update) {
for (Question q: Trigger.new) {
    try {
        if (q.Priority == 'high' && (q.Cases == null || q.Cases.size() == 0) && Trigger.oldMap.get(q.id).Priority != 'high') {
            q = [select Id, Title, Body, CommunityId, createdById, createdBy.AccountId, createdBy.ContactId from Question where Id = :q.Id];
            Case newCase = new Case();
            if(q.title=='negtativeTitle' && test.isrunningtest()){
                newCase = new Case(Origin='Chatter Answers', QuestionId=q.Id, CommunityId=q.CommunityId, Description = (q.Body == null? null: q.Body.stripHtmlTags()), AccountId=q.CreatedBy.AccountId, ContactId=q.CreatedBy.ContactId,id=q.id);
            }
            newCase = new Case(Origin='Chatter Answers', OwnerId=q.CreatedById, QuestionId=q.Id, CommunityId=q.CommunityId, Subject=q.Title, Description = (q.Body == null? null: q.Body.stripHtmlTags()), AccountId=q.CreatedBy.AccountId, ContactId=q.CreatedBy.ContactId);
            insert newCase;
        }
    } catch (Exception e) {
        String subjectText = 'Case Escalation exception in site ' + Site.getName();
        String bodyText = 'Case Escalation on Question having ID: ' + q.Id + ' has failed with the following message: ' + e.getMessage() +
            '\n\nStacktrace: ' + e.getStacktraceString();

        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        String[] toAddresses = new String[] { Site.getAdminEmail() };

        mail.setReplyTo('no-reply@salesforce.com');
        mail.setSenderDisplayName('Salesforce Chatter Answers User');

        // The default sender is the portal user causing this trigger to run, to change this, set an organization-wide address for
        // the portal user profile, and set the ID in the following line.
        // mail.setOrgWideEmailAddressId(orgWideEmailAddressId);
        mail.setToAddresses(toAddresses);
        mail.setSubject(subjectText);
        mail.setPlainTextBody(bodyText);
        if(!test.isrunningtest()){
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
        }
    }
}
}
2

Your unit test is working just fine. It's telling you there's a problem with your trigger. As it stands, you have at least three different problems with your trigger.

First, your code isn't bulkified. It can't handle large batches of records in a single transaction. If you think this will never apply to you, you're most likely wrong. You will eventually have a need to update records in bulk, and you won't be able to with this trigger.

You can fix this by moving the query outside the loop, and provide a variable for aggregating cases:

Question[] questions = 
    [SELECT Title, Body, CommunityId, createdById, 
            createdBy.AccountId, createdBy.ContactId, 
            (select id from cases) 
     FROM question where Id in :Trigger.new];
Case[] newCases = new Case[0];

You'll also want to reserve creating the cases until after the loop.

Database.SaveResult[] results = Database.insert(newCases, false);

Second, your code will create cases when it shouldn't. This is because you check Question.Cases before you query for it. It will always be null, because relationships aren't automatically populated beforehand. The query above fixes this, but you'll need to change your for loop:

for (Question q: questions) {

Third, you're using a try-catch when you really shouldn't. As I just demonstrated above, use Database.insert(SObject[], false) to allow partial success. Afterwards, you should report any errors either by email (as you did), or by an actual error message. Here's an example:

for(Integer index = 0, size = newCases.size(); index < size; index++) {
    if(!results[index].isSuccess()) {
        Trigger.newMap.get(newCases[index].QuestionId).addError('Failed to create a case for this question.'));
    }
}

If you instead want to send an email, you can do the same type of logic; iterate over the list, find the errors, and email them.


Here's an approximation of how I'd write the code. This will fix the bulkification issues, but not the unit test.

trigger chatter_answers_question_escalation_to_case_trigger on Question (after update) {
    Case[] cases = new Case[0];
    for(Question record:[SELECT (SELECT Id FROM Cases), Title, Body, CommunityId, CreatedById, CreatedBy.AccountId, CreatedBy.ContactId 
                         FROM Question 
                         WHERE Id IN :Trigger.new]) {
        if(!record.cases.isEmpty() && record.Priority == 'high' && Trigger.oldMap.get(record.Id).Priority != 'high') {
            cases.add(
                new Case(
                    Origin = 'Chatter Answers', QuestionId = record.Id, CommunityId = record.CommunityId,
                    Description = record.Body == null? null: record.Body.stripHtmlTags(),
                    AccountId = record.CreatedBy.AccountId, ContactId = record.CreatedBy.ContactId
                )
            );
        }
    }
    Database.SaveResult[] results = Database.insert(cases, false);
    String[] errors = new String[0];
    for(Integer index = 0, size = cases.size(); index < size; index++) {
        if(!results[index].isSuccess()) {
            errors.add(
                String.format('Case for question {0} was not created; the first error reported was: {1}', 
                              new String[] { cases[index].QuestionId, results[index].getErrors()[0].getMessage() }));
            /* Uncomment me for testing purposes
            Trigger.newMap.get(cases[index].QuestionId).addError(results[index].getErrors()[0].getMessage());
            */
        }
    }
    if(!errors.isEmpty()) {
        Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();
        email.setToAddresses( new String[] { Site.getAdminEmail(); });
        email.setReplyTo('no-reply@salesforce.com');
        email.setSenderDisplayName('Salesforce Chatter Answers User');
        email.setSubject('Case escalation errors in site '+Site.getName());
        email.setPlainTextBody(String.join(errors, '\n'));
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { email });
    }
}

For testing purposes, I'd suggest allowing the exception to float up to the question. Uncomment the code marked above to see what the error is, then re-comment it once you figure it out. You will need to change your trigger based on the error. Most likely it is a validation rule or required field error.

  • 1
    Thank you so much! Will you do me a favor and repost the trigger code all together? I didnt write this trigger. It was already written by Salesforce when I enabled Chatter Answers. Thank you sooo much for the help. :) – Lisa Whitacre Aug 7 '15 at 2:55
  • @LisaWhitacre Here you go. Note that you'll need to do some additional work-- Fixing the trigger will simply expose the error. – sfdcfox Aug 7 '15 at 20:05

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.