function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
DekorDekor 

MilestoneUtils test class failing

So I have created a Apex class called "MilestoneUtils" to use with some triggers I am using for entitlements.  I have also created a test class to ensure code coverage.  I grabbed the test class from the "MilestoneUtils" in the salesforce documentation but separated it into its own class as current salesforce version doesn't allow test class within your main class. 

When I try to run the test it fails with these two errors:

Class testCompleteMilestoneCase
Method Name testCompleteMilestoneCase
Pass/Fail Fail
Error Message System.QueryException: List has no rows for assignment to SObject
Stack Trace Class.testCompleteMilestoneCase.testCompleteMilestoneCase: line 6, column 1


and

Class testCompleteMilestoneCase
Method Name testCompleteMilestoneViaCase
Pass/Fail Fail
Error Message System.QueryException: List has no rows for assignment to SObject
Stack Trace Class.testCompleteMilestoneCase.testCompleteMilestoneViaCase: line 36, column 1


I can't understand why the list would not have any rows as surely the query returns the first record in the entilement/contact table and there is at least one contact/one entitlement in my sandbox. 

Here it the test class itself:
 
@isTest
    private class testCompleteMilestoneCase{
  
  static testMethod void testCompleteMilestoneCase(){
    
    Contact oContact = [select id from Contact limit 1];
    String contactId;
    if (oContact != null)
      contactId = oContact.Id;
    
    Entitlement entl = [select id from Entitlement limit 1];
    String entlId;
    if (entl != null)
      entlId = entl.Id;
    
    List<Case> cases = new List<Case>{};
    if (entlId != null){
      Case c = new Case(Subject = 'Test Case with Entitlement ', EntitlementId = entlId, ContactId = contactId);
      cases.add(c);
    }
    
    // Insert the Account records that cause the trigger to execute.
    if (cases.isEmpty()==false){
      insert cases;
      List<Id> caseIds = new List<Id>();
      for (Case cL : cases){
        caseIds.add(cL.Id);
      }
      milestoneUtils.completeMilestone(caseIds, 'First Response', System.now());
        }
    }
  
    static testMethod void testCompleteMilestoneViaCase(){
      
        // Perform data preparation
        Entitlement entl = [select id from Entitlement limit 1];
        String entlId;
        if (entl != null)
            entlId = entl.Id;
        List<Case> cases = new List<Case>{};
        for(Integer i = 0; i < 1; i++){
            Case c = new Case(Subject = 'Test Case ' + i);
            cases.add(c);
            if (entlId != null){
                c = new Case(Subject = 'Test Case with Entitlement ' + i, EntitlementId = entlId);
                cases.add(c);
            }
        }
        
        // Insert the Account records that cause the trigger to execute.
        insert cases;

        List<CaseComment> ccs = new List<CaseComment>{};
        for(Case c : cases){
            CaseComment cc = new CaseComment(CommentBody='TestPublic', IsPublished=true, ParentId=c.Id);
            ccs.add(cc);
            cc = new CaseComment(CommentBody='TestPrivate', IsPublished=false, ParentId=c.Id);
            ccs.add(cc);
        }
        if (ccs.isEmpty()==false)
            insert ccs;
    
    // Now create emailmessage objects for them.
    
        List<EmailMessage> emails = new List<EmailMessage>();
        for(Case c : cases){
            emails.add(new EmailMessage(parentId = c.id));
        }
        if(emails.isEmpty()==false)
            database.insert(emails);
        
        for(Case c : cases){
            Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
            String[] toAddr = new String[] {'mramsey@salesforce.com'};
            mail.setToAddresses(toAddr);
            mail.setSaveAsActivity(false);
            mail.setTargetObjectId(c.ContactId);
            mail.setWhatId(c.Id);
            mail.setHtmlBody('TestHTMLBody');
            mail.setPlainTextBody('TestTextBody');
            Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
        }
    
    for(Case c : cases){
      c.Status = 'Closed';
    }
    update cases;
    
        // Query the database for the newly inserted records.
        List<Case> insertedCases = [SELECT Subject,
                                           Description,
                                          (SELECT IsPublished, CommentBody From CaseComments),
                                          (SELECT TextBody, Subject, Incoming From EmailMessages)
                                           FROM Case
                                           WHERE Id IN :cases];
    }
}

Here it the main class:
 
public class milestoneUtils {
    
    public static void completeMilestone(List<Id> caseIds, String milestoneName, DateTime complDate) {
      
    List<CaseMilestone> cmsToUpdate = [select Id, completionDate
                       from CaseMilestone cm
                       where caseId in :caseIds and cm.MilestoneType.Name=:milestoneName and completionDate = null limit 1];
    if (cmsToUpdate.isEmpty() == false){
      for (CaseMilestone cm : cmsToUpdate){
        cm.completionDate = complDate;
      }
      update cmsToUpdate;
    } // end if
  }
  }


 
James LoghryJames Loghry
The test class you copied was likely before API version 18. Before 18, the test classes would see existing org data by default.  After 18, your tests could see existing data, but only with the @SeeAllData=true annotation.  When you create the new class, it usually defaults to the latest API version (or the latest version of whatever IDE you're using), hence the test is now broken.

To fix the test, you'll need to create mock records (contacts and perhaps entitlements) to accurately test the milestones code.
 
DekorDekor
Thanks James, thats useful information.  Any general guidelines you can point me at for creating test records during the test class execution?