+ Start a Discussion
Chris760Chris760 

Test Class Failing?

For some reason, the test class I've written is failing and I'm not sure why.  It seems to be failing as a result of one of the methods that the trigger calls.  What's weird though is that the method works fine when I'm not running it in test mode (just normally in the sandbox).  So I'm not sure if test mode disables something from working or what it might be, so any insights would be helpful.  Below is the method that the trigger is calling and failing, and the failure seems to be occuring on the third line where the records from the "Case_Assignment_Settings__c" SOQL list gets copied to the single Case_Assignment_Settings__c settings object (the test error is saying "System.ListException: List index out of bounds: 0, Class.caseAssignmentMethods: line 3, column 1,Trigger.caseTriggers: line 18, column 1: []"

Here is the caseAssignmentMethods class:
public class caseAssignmentMethods {
    public static list<Case_Assignment_Settings__c> caseSettings = [SELECT Hours_Until_Stale__c,Assignment_Timeout_Cutoff__c,Case_Match_Set_Size__c,Case_Origin_All_Match_Points__c,Case_Origin_Exact_Match_Points__c,Case_Origin_Exact_Match_Required__c,Location_All_Match_Points__c,Location_Exact_Match_Points__c,Location_Exact_Match_Required__c,Sub_Type_All_Match_Points__c,Sub_Type_Exact_Match_Points__c,Sub_Type_Exact_Match_Required__c,Tier_All_Match_Points__c,Tier_Exact_Match_Points__c,Tier_Exact_Match_Required__c,Times_Skipped_Multiplier__c,Time_Elapsed_Multiplier__c,Type_All_Match_Points__c,Type_Exact_Match_Points__c,Type_Exact_Match_Required__c,User_Type_All_Match_Points__c,User_Type_Exact_Match_Points__c,User_Type_Exact_Match_Required__c FROM Case_Assignment_Settings__c];
    Public static Case_Assignment_Settings__c settings = caseSettings[0];
    Public static Integer samples = settings.Case_Match_Set_Size__c.intValue();
    Public static list<String> filters = new list<String>{'Case_Origin','Location','Sub_Type','Type','Tier','User_Type'};
    public static datetime loginCutoff = System.Now().addHours(0-settings.Assignment_Timeout_Cutoff__c.intValue());
    public static list<Group> groups = [SELECT Id FROM Group WHERE Type = 'Queue' AND Name = 'Unassigned Queue'];
    public static Id uq = groups.get(0).Id;

    public static void sendToUnassignedQueue(list<Case> casesNeedingUQ){
        for(Case c : casesNeedingUQ){
            c.OwnerId = uq;
        }
    }
    
    public static void reassignStaleCases(){
        list<Case> processed = new list<Case>();
        for(Case c : [SELECT Id, OwnerId from Case where Status = 'New' AND Hours_Since_Last_Modified__c > :settings.Hours_Until_Stale__c]){
            Case nc = new Case();
            nc.Id = c.Id;
            nc.OwnerId = uq;
            processed.add(nc);
        }
		update processed;
    }
    
	public static void assignCases(){
		map<Id,map<String,Integer>> scores = new map<Id,Map<String,Integer>>();
        map<Integer,Integer> keys = new map<Integer,Integer>();
        list<Case> cases = new list<Case>();
        list<Case> processed = new list<Case>();
        Integer totCases = 0;
        Boolean process = false;
        Boolean query = true;
        System.debug('samples: '+samples);

        for(User u : [SELECT Id, Name, Email, Type__c, Sub_Type__c, User_Type__c, Case_Origin__c, Tier__c, Location__c, Profile.Name, LastLoginDate FROM User WHERE LastLoginDate != null AND LastLoginDate > :loginCutoff AND Id NOT IN (SELECT OwnerId FROM CASE WHERE (Status = 'In Progress' OR Status = 'New') AND OwnerId != null) ORDER BY LastLoginDate DESC NULLS LAST]){
            
            String finalQuery = buildCaseQuery(u);
            cases = Database.query(finalQuery);
            totCases = cases.size();
            System.debug('totCases: '+totCases);
            if(totCases != 0){
                process=true;
            }
            System.debug('process: '+process);
            if(process){
                Integer i = 0;
                Integer topIdIter = -1;
                Double topScore = -1;
                while(i < samples && i < totCases){
                    Case c = cases.get(i);
                    System.debug('Case Origin: '+c.Id);
                    Double curScore = compareFields(c,u);
                    System.debug('curScore: '+curScore);
                    if(curScore >= 0 && curScore > topScore){
                        topScore = curScore;
                        topIdIter = i;
                    }
                    i++;
                }
                i = 0;
                if(topIdIter >= 0){
                    Boolean finalize = true;
                    while(i <= topIdIter && finalize && i<totCases){
                        if(i == topIdIter){
                            cases[i].inProcess__c = false;
                            cases[i].OwnerId = u.Id;
                            cases[i].Assignment_Points__c = topScore;
                            processed.add(cases.remove(i));
                            totCases--;
                            finalize = false;
                        }
                        else{
                            Integer ts = cases.get(i).Times_Skipped__c.intValue();
                            cases[i].Times_Skipped__c = ts+1;
                            cases[i].inProcess__c = true;
                        }
                        i++;
                    }
                }
                i = 0;
       		 	while(totCases > 0 && cases[i].inProcess__c == true){
            		cases[i].inProcess__c = false;
            		processed.add(cases.remove(i));
            		totCases--;
        		}
        		if(processed.size() > 0){
            		update processed;
        		}
            }
        }
        
    }
	
    public static Double compareFields(Case c,User u){
    	Double curScore = 0;
        Boolean potentialCase = true;
        for(String f : filters){
            String uf = String.valueOf(u.get(f+'__c'));
            String cf = String.valueOf(c.get(f+'__c'));
            Double exactMatchPoints = Double.valueOf(settings.get(f+'_Exact_Match_Points__c'));
            Double allMatchPoints = Double.valueOf(settings.get(f+'_All_Match_Points__c'));
            Boolean exactMatchrequired = Boolean.valueOf(settings.get(f+'_Exact_Match_Required__c'));
            if(uf !=null && cf !=null && uf.contains(cf)){
                curScore += exactMatchPoints;
            }
            else if(uf !=null && cf !=null && !uf.contains('All') && exactMatchrequired){
                potentialCase = false;
            }
            else if(uf !=null && cf !=null && uf.contains('All')){
                curScore += allMatchPoints;
            }
    	}
        curScore += c.Times_Skipped__c != null ? (c.Times_Skipped__c * settings.Times_Skipped_Multiplier__c) : 0;
        curScore += c.Hours_Old__c != null ? (c.Hours_Old__c * settings.Time_Elapsed_Multiplier__c) : 0;
        if(potentialCase){
        	return curScore;
        }
        else{
            return -1;
        }
    }
    
    public static String buildCaseQuery(User u){
        Integer i = 0;
        String queryString = 'SELECT Case_Origin__c,Hours_Old__c,inProcess__c,Assignment_Points__c,CreatedDate,Location__c,OwnerId, Status,Sub_Type__c,Tier__c,Times_Skipped__c,Type__c,User_Type__c FROM Case WHERE Status = \'New\' AND OwnerId = \''+uq+'\'';
            for(String f : filters){
            String ors = '';
            String uf = String.valueOf(u.get(f+'__c'));
            System.debug('Query: '+queryString);
            Boolean exactMatchRequired = Boolean.valueOf(settings.get(f+'_Exact_Match_Required__c'));
            if(uf != null && !uf.contains('All')){
                if(exactMatchRequired){
                    List<String> filterValues = uf.split(';',-2);
                    Integer j = 0;
                    for(String fv : filterValues){
                        if(j==0){
                        	ors+=('('+f+'__c = null OR ('+f+'__c != null AND ('+f+'__c = \''+fv+'\'');
                        }
                        else{
                            ors+=(' OR '+f+'__c = \''+fv+'\'');
                        }
                        j++;
                    }
                    ors+=(')))');
                    if(String.isNotBlank(ors)){
                        queryString+= ' AND '+ors;
                    }
                }
            }
        }
        queryString += ' ORDER BY CreatedDate ASC NULLS LAST LIMIT '+samples;
        System.debug('Query: '+queryString);
        return queryString;
    }
}

Here's the trigger that calls the above methods:

trigger caseTriggers on Case (before update, before insert, after insert, after update) {
    list<Case> cases = trigger.new;
    list<Case> assignedCases = new list<Case>();
    set<Id> userIds = new set<Id>();
    for(Case c : cases){
        userIds.add(c.OwnerId);
    }
    map<Id,User> userMap = new map<Id,User>([SELECT Id, Tier__c FROM User WHERE Id IN :userIds]);
    Boolean caseChanged = false;
    for(Case c : cases){
        if((c.Status == 'New' && (trigger.isInsert && trigger.isBefore || (trigger.isUpdate && trigger.isBefore && c.OwnerId == Trigger.oldMap.get(c.Id).OwnerId))) || (trigger.isUpdate && trigger.isBefore && c.isClosed == false && c.Tier__c != Trigger.oldMap.get(c.Id).Tier__c && !userMap.get(c.OwnerId).Tier__c.contains(c.Tier__c))){
            assignedCases.add(c);
        }
        if(trigger.isAfter){caseChanged = true;
        }
    }
    if(trigger.isBefore && !assignedCases.isEmpty()){
        caseAssignmentMethods.sendToUnassignedQueue(assignedCases);
    }
    if(true==true && triggerValidate.allowCaseUpdate && caseChanged){triggerValidate.allowCaseUpdate = false;caseAssignmentMethods.assignCases();triggerValidate.allowCaseUpdate = true;
    }
}

And lastly, here's my test class:

@isTest 
public class testAllCaseTrigger{

    static testMethod void testInactivityMethod() { 
    List<RecordType> rtypes = [Select Id From RecordType where Name='Person Account' and isActive=true];
    List<Account> accounts = new List<Account>{}; 
    List<Case> cases = new List<Case>{}; 
    
    test.startTest(); 
    
    for(Integer i = 0; i < 1; i++){ 
    Account newAcct = new Account(LastName='TestAcct'+ i,Phone='111',RecordTypeID=rtypes[0].ID);  
    accounts.add(newAcct); 
    } 
    
    insert accounts; 
    
    for(Integer i = 0; i < 1; i++){ 
    Case newCase = new Case(SuppliedName='TestAcct'+ i,Subject='111');  
    cases.add(newCase); 
    } 
    
    insert cases; 
    
    
    test.stopTest(); 
    
    }
    
    static testMethod void testCaseAssignment() {
        list<Profile> profiles = [SELECT Id FROM Profile WHERE Name = 'Service Rep'];
        Id profile = profiles[0].Id;        
        
      	User u = new User();
        u.LastName = 'Test';
        u.FirstName = 'Test';
        u.Email = 'abc13@123.com';
        u.ProfileId = profile;
        u.Tier__c = 'Tier 1';
        u.Username = 'abc13@123.com';
        u.Alias = 'Test1';
        u.CommunityNickname = 'TestNick';
        u.TimeZoneSidKey = 'America/Los_Angeles';
        u.LocaleSidKey = 'en_US';
        u.EmailEncodingKey = 'ISO-8859-1';
        u.LanguageLocaleKey = 'en_US';
        Insert u;
        
        User u2 = new User();
        u2.LastName = 'Test2';
        u2.FirstName = 'Test2';
        u2.Email = 'abcd2@123.com';
        u2.ProfileId = profile;
        u2.Tier__c = 'Tier 2';
        u2.Username = 'abcd2@123.com';
        u2.Alias = 'Test2';
        u2.CommunityNickname = 'TestNick2';
        u2.TimeZoneSidKey = 'America/Los_Angeles';
        u2.LocaleSidKey = 'en_US';
        u2.EmailEncodingKey = 'ISO-8859-1';
        u2.LanguageLocaleKey = 'en_US';
        Insert u2;
        
        test.startTest(); 
        
        Case c = new Case();
        c.OwnerId = u.Id;
      	c.Status = 'New';
      	c.Tier__c = 'Tier 1';
   		Insert c;
        
        c.Status = 'In Progress';
        Update c;
        
        c.Tier__c = 'Tier 2';
        Update c;
        test.stopTest(); 
        
   	}

}

Thanks.

Best Answer chosen by Chris760
Ankush DurejaAnkush Dureja
You are querying 'Case_Assignment_Settings__c' in your query in test class using these two lines
public static list<Case_Assignment_Settings__c> caseSettings = [SELECT Hours_Until_Stale__c,Assignment_Timeout_Cutoff__c,Case_Match_Set_Size__c,Case_Origin_All_Match_Points__c,Case_Origin_Exact_Match_Points__c,Case_Origin_Exact_Match_Required__c,Location_All_Match_Points__c,Location_Exact_Match_Points__c,Location_Exact_Match_Required__c,Sub_Type_All_Match_Points__c,Sub_Type_Exact_Match_Points__c,Sub_Type_Exact_Match_Required__c,Tier_All_Match_Points__c,Tier_Exact_Match_Points__c,Tier_Exact_Match_Required__c,Times_Skipped_Multiplier__c,Time_Elapsed_Multiplier__c,Type_All_Match_Points__c,Type_Exact_Match_Points__c,Type_Exact_Match_Required__c,User_Type_All_Match_Points__c,User_Type_Exact_Match_Points__c,User_Type_Exact_Match_Required__c FROM Case_Assignment_Settings__c];
Public static Case_Assignment_Settings__c settings = caseSettings[0];
But there is no data created for 'Case_Assignment_Settings__c'. So there are two solutions
1. You can use @isTest(SeeAllData=true) annotation in test class.
2. Second solution is that first you need to insert 'Case_Assignment_Settings__c' in your test class, then you can query it.



All Answers

Shashikant SharmaShashikant Sharma
There are two things you needs to do :

1. Insert Case_Assignment_Settings__c data in your test class
2. Change Public static Case_Assignment_Settings__c settings = caseSettings[0];

to 
Public static Case_Assignment_Settings__c settings = caseSettings.size() > 0 ? caseSettings[0] : new Case_Assignment_Settings__c();

Ankush DurejaAnkush Dureja
You are querying 'Case_Assignment_Settings__c' in your query in test class using these two lines
public static list<Case_Assignment_Settings__c> caseSettings = [SELECT Hours_Until_Stale__c,Assignment_Timeout_Cutoff__c,Case_Match_Set_Size__c,Case_Origin_All_Match_Points__c,Case_Origin_Exact_Match_Points__c,Case_Origin_Exact_Match_Required__c,Location_All_Match_Points__c,Location_Exact_Match_Points__c,Location_Exact_Match_Required__c,Sub_Type_All_Match_Points__c,Sub_Type_Exact_Match_Points__c,Sub_Type_Exact_Match_Required__c,Tier_All_Match_Points__c,Tier_Exact_Match_Points__c,Tier_Exact_Match_Required__c,Times_Skipped_Multiplier__c,Time_Elapsed_Multiplier__c,Type_All_Match_Points__c,Type_Exact_Match_Points__c,Type_Exact_Match_Required__c,User_Type_All_Match_Points__c,User_Type_Exact_Match_Points__c,User_Type_Exact_Match_Required__c FROM Case_Assignment_Settings__c];
Public static Case_Assignment_Settings__c settings = caseSettings[0];
But there is no data created for 'Case_Assignment_Settings__c'. So there are two solutions
1. You can use @isTest(SeeAllData=true) annotation in test class.
2. Second solution is that first you need to insert 'Case_Assignment_Settings__c' in your test class, then you can query it.



This was selected as the best answer
Chris760Chris760
Thanks both Shashikant and Ankush, it worked perfectly!  And thanks so much Ankush for telling me about the SeeAllData annotation.  For my purposes, that will make implementing this 100 times easier as opposed to populating a ton of custom settings in the test class.

Thanks again!