+ Start a Discussion
Oldwen AdrianoOldwen Adriano 

Need help writing a Test class for this class

Could someone please give me a hand writing a test class for this class below?

-----------------------------------------------------------------
global class ControllerGetNext {

List<Task> tList = new List<Task>();

List<wrapper> lstw = new List<wrapper>();

List<wrapper> lstwPage = new List<wrapper>();

//----------------------------------------------------------

//Campaign

List<Campaign__c> cList = new List<Campaign__c>();

public string userselected{get;set;} //I have it declared here as a public variable in the controller

public List<selectOption> useroptions{get;set;}

//----------------------------------------------------------

public ControllerGetNext()

{

// integer nextcount=0;

nextvisible = false;

previsible = true;

page=0;

system.debug('nextvisible=='+nextvisible);

//----------------------------------------------------------

//Campaign

//When the controller instatiates this is called as expected.

useroptions = new list<selectoption>();

cList = [Select ID, Campaign_Name__c from Campaign__c];

for(integer i=0; i < cList.size(); i++)

{

useroptions.add(new SelectOption(cList[i].ID, cList[i].Campaign_Name__c));

}

//----------------------------------------------------------

}

Contact cContact;

Lead lLead;

public List<wrapper> lstWrapperString{

get{return getTasks();}

}

//lstWrapperString

//getTasks

Public List<wrapper> getTasks()

{

lstw.clear();

tList = [Select ID, Subject, ActivityDate, Due_Time__c, Description, WhoID from Task where OwnerId =: UserInfo.getUserId() And Status != 'Completed']; //All of the users tasks

if(!tList.isEmpty())

{

for(integer i=0; i < tList.size(); i++) //Loop thru the tasks and add to list

{

string strPhone = '';

string LeadName = '';

decimal iAttepmts = 0;

try

{

cContact = [SELECT Phone FROM Contact WHERE Id = : tList[i].WhoID]; //The phone is in the contact object which is related to the Lead

strPhone = cContact.Phone;

}

catch(exception e)

{

strPhone = 'Not Provided';

}

try

{

lLead = [SELECT Name, Attempts__c FROM Lead WHERE Id = : tList[i].WhoID];

LeadName = lLead.Name;

iAttepmts = lLead.Attempts__c;

}

catch(exception e)

{

LeadName = 'Not Provided';

iAttepmts = 0;

}

if(iAttepmts < 20) //Business rule for less than 20 attemps.

{

lstw.add(new wrapper(tList[i].ID, LeadName, tList[i].ActivityDate, tList[i].Due_Time__c, tList[i].Description, strPhone));

}

}

}

return lstw;

}

//*******************************************************************************************************

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

//Create my wrapper class... like an ENUM

Public class wrapper

{

public string tID{get;set;}

public string tSubject{get;set;}

public date tActivityDate{get;set;}

public string tDueTime{get;set;}

public string tDescription{get;set;}

public string tPhone{get;set;}

//Constructor

public wrapper(string tID, string tSubject, date tActivityDate, string tDueTime, string tDescription, string tPhone)

{

this.tID = tID;

this.tSubject = tSubject;

this.tActivityDate = tActivityDate;

this.tDueTime = tDueTime;

this.tDescription = tDescription;

this.tPhone = tPhone;

}

}

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

//***********************************************************

//Page navigation actions

//***********************************************************

public integer page=0;

public boolean exfor = true;

public integer nextcount=0;

public List<integer> previouscount = new Integer[100];

public boolean previsible{get;set;}

public boolean nextvisible{get;set;}

public pagereference NextPage()

{

page ++;

exfor = true;

lstwPage = getTasks();

return null;

}

public pagereference previousPage()

{

page--;

nextcount = previouscount.get(page);

system.debug('nextcount'+nextcount);

exfor = true;

lstwPage = getTasks();

return null;

}

//**********************************************************

webService static String GetNextProcess(string ddlCampaignParam) {

//Lead variable used to assign it

Lead assignLead = null;

boolean foundLead = false;

Area_Code__c myTimeZone;

User myUser;

string strLead;

string workPhone;

string myArea;

string strTimeZone;

//Twice in one day variables

Date callDate1;

Date callDate2;

boolean setDate1 = false;

boolean setDate2 = false;

Campaign__c myCamp;

try

{

//Lets get the ID for the dserv user to be used in our query

myUser = [Select Id from User Where Alias = 'dserv'];

//Lets get the name of the Campaign

myCamp = [Select Campaign_Name__c from Campaign__c Where ID =: ddlCampaignParam];

//return 'Error: User name is: ' + UserInfo.getUserId();

//****************************************************************************

//Rule #1 : Pull all the leads that have not been called 4 times or more yet and order then from least to greatest.

//****************************************************************************

list<Lead> lstLeadToAssign = [Select Id, Phone, Lead_Start_Time__c, Lead_End_Time__c from Lead Where (Attempts__c < 5 Or Attempts__c = null) And Final_Flag__c != true And PCB_Flag__c != true And OwnerId =: myUser.Id And Campaign__c =: myCamp.Campaign_Name__c Order By Attempts__c ASC Limit 50];

//return 'Error: Lead size is : ' + lstLeadToAssign.size();

if(lstLeadToAssign.IsEmpty() == false)

{

for(integer i=0; i < lstLeadToAssign.size(); i++)

{

try

{

//----------------------------------------------------------------

//Get the phone num so we can check timezone for call availability against area code table.

//-----------------------------------------------------------------

try

{

workPhone = lstLeadToAssign[i].Phone;

//return 'Error: I got here after phone' + workPhone;

myArea = workPhone.substring(1, 4); //assumes the format is (210)

//return 'Error: I got here ';

}

catch(exception e)

{

continue;

}

try

{

myTimeZone = [Select TimeZone__c from Area_Code__c Where Name =: myArea];

strTimeZone = myTimeZone.TimeZone__c;

}

catch(exception e)

{

return 'Error: No Time Zone info in Area code table -- ' + e;

}

//****************************************************************************

//Rule #2 : Check to make sure that lead is in a callable time zone.

//****************************************************************************

if(AllowedZone(strTimeZone) == true)

{

//return 'Error: I got here';

foundLead = true;

strLead = lstLeadToAssign[i].Id;

//***************************************************************************************

//Rule- only twice in one day : Check to make sure.

//***************************************************************************************

if(lstLeadToAssign[i].Lead_Start_Time__c != null)

{

callDate1 = lstLeadToAssign[i].Lead_Start_Time__c;

if(callDate1 == date.today())

{

//This means, they have been called once today already. So we will check to see if they've been called twice.

if(lstLeadToAssign[i].Lead_End_Time__c != null)

{

callDate2 = lstLeadToAssign[i].Lead_End_Time__c;

if(callDate2 == date.today())

{

//They have already been called twice today so we move on to the next lead.

foundLead = false;

}

else

{

setDate2 = true;

}

}

else

{

setDate2 = true;

setDate1 = false;

}

}

else

{

setDate1 = true;

}

}

else

{

//If Date from Start time was null, then we will set this as our first date.

setDate1 = true;

}

//***************************************************************************************

}

//If lead was found lets go ahead and assign it to the user and and return it and end the process.

if(foundLead == true)

{

assignLead = [Select Id, Lead_Start_Time__c, Attempts__c, Lead_End_Time__c from Lead Where Id =: strLead for update];

try

{

assignLead.OwnerId = UserInfo.getUserId();

//return 'Error: Lead.OwnerId - ' + assignLead.OwnerId;

}

catch(exception e)

{

return 'Error: Could not find your user information!';

}

//***************************************************************************

//Assign our 24 hour period variables

//***************************************************************************

try

{

if(setDate1 == true)

{

assignLead.Lead_Start_Time__c = date.today();

}

if(setDate2 == true)

{

assignLead.Lead_End_Time__c = date.today();

}

}

catch(exception e)

{

return 'Error: On 24 hour date reference! - ' + e;

}

//***************************************************************************

if(assignLead.Attempts__c == null)

{

assignLead.Attempts__c = 1;

}

else

{

assignLead.Attempts__c = assignLead.Attempts__c + 1;

}

update assignLead;

return strLead;

}

}

catch(exception e)

{

return 'Error: inside the last lead found!' + e;

}

}

}

}

catch(exception e)

{

return 'Error: Currently, there is no Lead to assign!';

}

return 'Error: Currently, there is no Lead to assign!';

}

//Function to determine which timezones are currently allowed for calling

public static boolean AllowedZone(string myZone)

{

//return true;

DateTime myDate = DateTime.Now(); //Since the server lives in the EST timezone, you will get an EST time

Integer myStart = 9; //Calls start at 9am

Integer myEnd = 16; //Cannot call later than 5pm

Integer myHour = myDate.Hour(); //Get the current hour.

//Adjust the hour based on the time zone that was passed. EST is the base time zone.

if(myZone == 'CST')

{

myHour = myHour - 1;

}

if(myZone == 'MST')

{

myHour = myHour - 2;

}

if(myZone == 'PST')

{

myHour = myHour - 3;

}

if(myHour < myStart || myHour > myEnd)

{

return false;

}

else

{

return true;

}

}

}
--------------------------------------------------------------------------------------------------------------------------
pconpcon
Since writing a test class to cover all of the facets of this class is not something that anyone on here will do for you, I can give you some pointers and hopefully get you started.  I would recommend that you do some reading on testing [1] [2] [3] [4] to get a better understanding.  Each of your individual tests should only tests one specific portion of you class (ie a constructor test, sendEmail test, contactSelected test, etc).  You should also have both a postitive (everything works perfectly) and a negative (things are not right) test.

Each test should follow the following structure:
  • Setup of test data. This includes creation of any data needed by your class.  Account, Contacts etc
  • Starting the test. This is calling Test.startTest() to reset the governor limits
  • Calling your class / method
  • Stopping the test.This is calling Test.stopTest() to reset the governor limits and allow for any async jobs to finish
  • Asserting that your changes have worked
    • If you have inserted/updated/deleted data, you need to query for the updates
    • Run System.assert, System.assertEquals, System.assertNotEquals to verify that you got the correct data back
If you have any specific problems with your tests, feel free to create a new post with the part of the class you are trying to test and your current test method, and you will more likely get a better response then asking for someone to essentially write an entire test class for you.

Also, in the future, please use the "Add a code sample" button (icon <>) to increase code readability.  Also, try to ask specific questions about issues you have when writing tests, not just "write my tests for me"

[1] http://www.sfdc99.com/2013/05/14/how-to-write-a-test-class/
[2] http://pcon.github.io/presentations/testing/
[3] http://http://blog.deadlypenguin.com/blog/2014/07/23/intro-to-apex-auto-converting-leads-in-a-trigger/
[4] http://blog.deadlypenguin.com/blog/testing/strategies/
Oldwen AdrianoOldwen Adriano
pcon:  I wasn't asking for anyone to write a test class for me.  I was asking for help so I can write it myself.  I have spent many hours already researching testing and the typical problem I've found is as a class increases in complexity, the test case examples on the net are less.  Some of what you posted above is helpful, but mostly it's the same problem.  All examples are simple and do not delve into complex code or address complex issues.  Also, there is a lot of examples for triggers and ironcially, test classes for triggers are simple.

Also, in the future, please note that any posts from me asking for help is just that.  I'm asking for help, not for anyone to do the work for me.  I am looking for guidance, collaboration, ideas, and suggestions from experienced SFers.

If you have any guidance for me for this particular class, I am a willing sponge.

Thank you
pconpcon
I'm sorry if my response seemed crass or terse, but there are lots of posts on this forum where people ask for test code to be written for them.  You request was simply "Could someone please give me a hand writing a test class for this class below?" and then a wall of code.  If you wanted help learning how to write test cases then I would suggest that you expand upon your initial one sentence and explain what you have done and where you are having problems.  Additionally, I would include any tests that you have written and narrow down the focus of your question to a specific portion of your code that you are having problems with.  Including an entire class with no context will make it likely that nobody will even respond to your post.

With that out of the way, the fourth link I included above talks about strategies for testing complex code and would be easily applied to your code you included.  You would create individual test methods for the following methods
  • Constructor
  • 1stWrapperString
  • Wrapper Constructor
  • nextPage
  • previousPage
  • getNextProcess
  • allowedZone
Then you'll create multiple version of each of those tests to cover each of your facets.  For example a CST, PST and MST test for allowedZone.  Of these you'll have the most for getNextProcess.

You do not (and should not) have one giant test for all of these methods.
Oldwen AdrianoOldwen Adriano
Thank you very much for your reply...  This is very helpful.  I will start with the constructor.  Just to make sure I'm on the correct path, this is as simple as instantiating an object that's an instance of my class?  I believe I am over complicating the test process, but it's so foreign to me that I want to ask the simple questions to make sure I understand. 

On another note, I have a question you may very well know.  I am using the Eclipse IDE and when I run my tests, I do not see my class in the list.  It appears to only be capturing my triggers.  Do you know how I might resolve this?

User-added image

Thank you.
pconpcon
Right, you'll instantiate a copy of the class between a Test.startTest() and a Test.stopTest() then assert that the values in your class were set correctly by your constructor using System.assertEquals.  If your variables are private you will need to add the @testVisible [1] notation to them in order to access them directly in your test but not access them directly in other code.

As for the Eclipse question, I do not know.  I do not use Eclipse and run all of my tests via either the developer console or via setup -> develop -> apex test execution.

[1] https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_annotation_testvisible.htm
Oldwen AdrianoOldwen Adriano
Nice, that 1st one was helpful.  I'm moving and understanding it more now.  So my first issue where I'm having trouble is this...  The IDE tell me I have no coverage for this line:
public string userselected{get;set;}
So this line of code is simply a property.  Do I create a test that simply sets the string value and gets it to get code coverage?

Thanks.....
 
pconpcon
I would not worry about testing that line directly.  I would just ensure that one of the methods you are testing sets the String and then that one of the methods you are using gets the String.  If you want to test it directly you can simply do the set and then do a System.assertEquals on it directly afterwards inside your start/stopTest
Oldwen AdrianoOldwen Adriano
I am running into this error:

Save error: Static methods cannot be invoked through an object instance
 
static testMethod void Class_ControllerGetNext_AllowedZone_TM()
	{
		DateTime myDate = DateTime.Now(); //Since the server lives in the EST timezone, you will get an EST time
        
        Integer myStart = 9; //Calls start at 9am
        Integer myEnd = 16; //Cannot call later than 5pm
        
        Integer myHour = myDate.Hour(); //Get the current hour.
        //---------------------------------------------------------------------------------------------
        
		// Start the test.
        test.startTest();
		
		ControllerGetNext objGetNext = new ControllerGetNext();
		
		boolean myZoneReturn = objGetNext.AllowedZone('CST');
		boolean myZoneReturn2 = objGetNext.AllowedZone('MST');
		boolean myZoneReturn3 = objGetNext.AllowedZone('PST');
		
		// Stop the test.
        test.stopTest();
        
        myHour = myHour - 1;
        if(myHour < myStart || myHour > myEnd)  //CST
        {
            System.assertEquals(true, myZoneReturn);
        }
        
        myHour = myHour - 1;
        if(myHour < myStart || myHour > myEnd)  //MST
        {
            System.assertEquals(true, myZoneReturn);
        }
        
        myHour = myHour - 1;
        if(myHour < myStart || myHour > myEnd)  //PST
        {
            System.assertEquals(true, myZoneReturn);
        }
	}

The error occurs on the objGetNext.AllowedZone();
 
//Function to determine which timezones are currently allowed for calling
    public static boolean AllowedZone(string myZone)
    {
        //return true;
        DateTime myDate = DateTime.Now(); //Since the server lives in the EST timezone, you will get an EST time
        
        Integer myStart = 9; //Calls start at 9am
        Integer myEnd = 16; //Cannot call later than 5pm
        
        Integer myHour = myDate.Hour(); //Get the current hour.
        
        //Adjust the hour based on the time zone that was passed.  EST is the base time zone.
        if(myZone == 'CST')
        {
            myHour = myHour - 1;
        }
            
        if(myZone == 'MST')
        {
            myHour = myHour - 2;
        }
            
        if(myZone == 'PST')
        {
            myHour = myHour - 3;
        }
        
        
        if(myHour < myStart || myHour > myEnd)
        {
            return false;
        }
        else
        {
            return true;
        }
    }

 
Oldwen AdrianoOldwen Adriano
Pcon... I got past that last one... Just had to adjust from object to direct call because of static.  I am having trouble with the lstWrapper... I am not even sure where to begin on this one....  Thanks!!
Oldwen AdrianoOldwen Adriano
Hi Pcon:  Can you get me started with the lstWrapper?  I dont' fully understand how to test this item.

Thank you!
pconpcon
I'm sorry, you caught me yesterday at the end of my day and did not have a chance to respond in the evening.

To test the wrapper class, you would do just like you did for your normal constructor except you would call it one level deeper
 
public testMethod void wrapperConstructor() {
    String testTID = 'idString';
    String testSubject = 'testSubject';
    Date testDate = Date.today().addDays(-1);
    String testDueTime = 'dueTime';
    String testDescription = 'testDescription';
    String testPhone = 'testPhone';

    Test.startTest();

    ControllerGetNext.wrapper wrapper = new ControllerGetNext.wrapper(testTID, testSubject, testDate, testDueTime, testDescription, testPhone);

    Test.stopTest();

    System.assertEquals(testTID, wrapper.tID, 'TID was not set correctly');
    System.assertEquals(testSubject, wrapper.tSubject, 'subject was not set correctly');
    System.assert(testDate.isSameDay(wrapper.tActivityDate), 'activity date was not set correctly');
    System.assertEquals(testDueTime, wrapper.tDueTime, 'Due time was not set correctly');
    System.assertEquals(testDescription, wrapper.tDescription, 'description was not set correctly');
    System.assertEquals(testPhone, wrapper.tPhone, 'phone was not set correctly');
}
Oldwen AdrianoOldwen Adriano
pcon, you are so very helpful... I got the wrapper contructor working.  So on to the Get Tasks function test.  Below is what I have so far, but I am falling short somehwere.
 
static testMethod void Class_ControllerGetNext_TM()
	{
		//We are going to run this test as an agent.
		Profile p = [Select id,Name from Profile where name ='Agent'];
		
		//Create a new user with the Agent profile...
		User u =    new User(Alias = 'stdt', Email='deliveryservice@alorica.com.fdc', EmailEncodingKey='UTF-8', LastName='Testing', LanguageLocaleKey='en_US', LocaleSidKey='en_US', 
		 			ProfileId = p.Id, TimeZoneSidKey='America/Los_Angeles',UserName='oldwentester@alorica.com');
                     
        insert u;        
        
        User myDserv;
        //Lets get the ID for the dserv user to be used in our query        	
        myDserv = [Select Id from User Where Alias = 'dserv'];
        	
        
		//Get the user create above.
        User myUser = [Select Id, LastName, FirstName, Alias from User Where UserName='oldwentester@alorica.com'];
        
        //********************************************************************************************************
        //Must follow the correct order of creation for relationships and triggers to properly process.
        //********************************************************************************************************
        
        //Create a new lead for testing
        Lead newLead = new Lead(OwnerId = myDserv.Id, FirstName = 'Unit', LastName = 'Testing', Phone = '(210)555-1212', Email = 'tester@alorica.com', Company = 'Alorica', Campaign__c = 'IWS Master');
        insert newLead;
        
        //After the lead was inserted above the trigger to create the contact will fire and you will also have a contact record.
        
        Lead getLead = [Select Id, OwnerId, FirstName, LastName, Phone from Lead Where FirstName = 'Unit' And LastName = 'Testing'];
        
        //Create a task that is assigned to the user created above
        Task t = new Task(WhoId = getLead.Id, Subject = 'From Test Class', Status = 'In Progress', PCB_Flag__c = true, OwnerId = myUser.Id, ActivityDate = Date.today());
        
        //-------------------------------------------------------------------------------------------------------------------------------------
        //Test the Get Tasks portion of the Controller get next class
        //-------------------------------------------------------------------------------------------------------------------------------------
        
         System.runAs(u)
         {
         	Test.startTest();
         	
         	ControllerGetNext objGetNext = new ControllerGetNext();
         	objGetNext.getTasks();
         	
         	Test.stopTest();
         }
        
        //-------------------------------------------------------------------------------------------------------------------------------------
        
	}

 
pconpcon
So you need to assign the result of getTasks to something and then assert that you got the right thing back.  (Also I would move the constructor out of the start/stopTest since you're not testing that.
 
static testMethod void Class_ControllerGetNext_TM() {
    // Setup stuff

    // Defining this outside of the runAs so that it is in scope for our asserts
    List<ControllerGetNext.Wrapper> results;

    System.runAs(u) {
        ControllerGetNext controller = new ControllerGetNext();

        Test.startTest();

        results = controller.getTasks();

        Test.stopTest();
    }

    System.assertEquals(1, results.size(), 'Did not get the expected number of tasks back');
    // Additional asserts to make sure we got the right task back
}

 
Oldwen AdrianoOldwen Adriano
Hi pcon:  I've come a long way and have gotten a lot done.  My code coverage is up to 75% and I've also learned some things along the way.  My next hurdle is the page reference test.  It appears that ore is required than just the call to the controller and method.  Can you please point me in the right direction?

Thanks,
Oldwen
pconpcon
Right, since your page reference methods are returning null, you'll mainly be asserting that as well as asserting that page, exfor, lstwPage and nextcount variables are set correctly
 
// Code to set up tasks and whatnot

ControllerGetNext controller = new ControllerGetNext();

Test.startTest();

PageReference result = controller.nextPage();

Test.stopTest();

System.assertEquals(null, result, 'Did not get the right page reference back');
System.assertEquals(1, controller.page, 'The page number should have incremented');
System.assert(controller.exfor, 'exfor should be set to true');
//Assert for size and contents of lstwPage

Then to make sure it works for multiple pages
 
// Code to set up tasks and whatnot

ControllerGetNext controller = new ControllerGetNext();
controller.nextPage();
controller.nextPage();

Test.startTest();

PageReference result = controller.nextPage();

Test.stopTest();

System.assertEquals(null, result, 'Did not get the right page reference back');
System.assertEquals(3, controller.page, 'The page number should have incremented');
System.assert(controller.exfor, 'exfor should be set to true');
//Assert for size and contents of lstwPage

Then do something similar for the previousPage method.

I would recommend adding a test for previousPage when your on page 0 and a nextPage test when you're on the last page.  Just to make sure they do the right things.
Oldwen AdrianoOldwen Adriano
Hi pcon,

I'm happy to report that I have 93% code coverage accross all my classes and you were a wonderful help to allow me to accomplish that.  I would like to call upon your expertise again.  Could you please take a look at a new questions I posted and see if you can help?

Thank you very much....

https://developer.salesforce.com/forums/ForumsMain?id=906F0000000BSSiIAO
 
pconpcon
Glad to hear! If you don't mind, can you then please pick what you think is the "best answer" on this post and choose that.  Just so that it is removed from the unanswered queue.