+ Start a Discussion
tgk1tgk1 

Tricky test class

Hi all - I'm having trouble writing a test class for the following apex code:

 

trigger LastSWDate on Task (after insert, after update) {
  
  
  //To do - If the subject of a completed task contains "SW", put the date of the completed task in the 
  //the "Last_SW_Activity__c" field on the account object

//Create a set of related account ID's
Set <ID> acctIDs = new Set <ID> ();


//For every task, add it's related to account ID to the set
  for (Task t: Trigger.new){
    acctIDs.add(t.accountID);
//Create a map to match the task related to ID's with their corresponding account ID's
    Map<ID, Account> acctMap = new Map<ID, Account> ([Select ID, Last_SW_Activity__c from Account where ID in :acctIDs]);
//Create the account object
      Account acctRec = acctMap.get(t.accountID);

//If the account ID isn't null, the subject line starts with "sw", and the task has been marked as completed    
  If ((t.accountID != null) &&(t.subject.indexOf('sw')==0) && (t.Status == 'Completed'))
//Check to see if the Last_SW_Activity__c field is current compared with the latest completed activity
      If (acctMap.get(t.accountID).Last_SW_Activity__c < t.LastModifiedDate || acctMap.get(t.accountID).Last_SW_Activity__c ==null){
//Update the Last_SW_Activity__c field on the account object with the task's end date  
        acctrec.Last_SW_Activity__c = t.LastModifiedDate;
        update acctRec;
    }
  }
}

 Can somebody please help take a stab at a test class for this?  I would really appreciate it!  Thanks!

Best Answer chosen by Admin (Salesforce Developers) 
JimRaeJimRae

Yes, that would do it.  The system Date/Time method wouldn't work correctly, as it would always be a few seconds after the task was inserted.

 

system.assert(checkAcct.Last_SW_Activity__c > Datetime.now().addMinutes(-10),'\n\nERROR: Date not updated correctly');

This will test to see if the LastSw Activite date is greater than 10 minutes ago, you could tweak this if your test case is running too slow, but this should get it done.

All Answers

JimRaeJimRae

One comment about your trigger, it is not very bulk safe.  If a lot of tasks were to be added in batch, you would likely get a DML limit error, because you are updating each account as a separate update.  You should add each of the updated accounts to a list, and then update the list in one DML statement, like this:

 

trigger LastSWDate on Task (after insert, after update) {
 
  //To do - If the subject of a completed task contains "SW", put the date of the completed task in the 
  //the "Last_SW_Activity__c" field on the account object

//Create a set of related account ID's
Set <ID> acctIDs = new Set <ID> ();
//Create a list to hold the Updated Accounts
List<Account> updAccts = new List<Account>();

//For every task, add it's related to account ID to the set
  for (Task t: Trigger.new){
    acctIDs.add(t.accountID);
//Create a map to match the task related to ID's with their corresponding account ID's
    Map<ID, Account> acctMap = new Map<ID, Account> ([Select ID, Last_SW_Activity__c from Account where ID in :acctIDs]);
//Create the account object
      Account acctRec = acctMap.get(t.accountID);

//If the account ID isn't null, the subject line starts with "sw", and the task has been marked as completed    
  If ((t.accountID != null) &&(t.subject.indexOf('sw')==0) && (t.Status == 'Completed'))
//Check to see if the Last_SW_Activity__c field is current compared with the latest completed activity
      If (acctMap.get(t.accountID).Last_SW_Activity__c < t.LastModifiedDate || acctMap.get(t.accountID).Last_SW_Activity__c ==null){
//Update the Last_SW_Activity__c field on the account object with the task's end date  
        acctrec.Last_SW_Activity__c = t.LastModifiedDate;
        updAccts.add(acctrec);
    }
  }
  update updAccts;
}

 

JimRaeJimRae

Here is a stab at a test class, might need some tweaking, I don't have those fields in my org, and don't know what required fields you might have on the Account or Task creation:

 

/**
 * Test Class for the LastSWDate Task Trigger
 * To do - If the subject of a completed task contains "SW", put the date of the completed task in the 
 * the "Last_SW_Activity__c" field on the account object
 * Created 8/30/2011
 * 
 */
@isTest
private class LastSWDateTest {

    static testMethod void myUnitTest() {
		//Setup
		Date lastSWDate = Date.newInstance(2009,01,01);//make this in the past to insure the test works correctly
		Account tAcct = new Account(name='Test Account',Last_SW_Activity__c=lastSWDate);//you might need to add more required fields to this
		try{
			insert tAcct;
		}catch(DMLException d1){
			system.assert(false,'\n\nERROR INSERTING TEST ACCOUNT:'+d1.getDMLMessage(0));
		}
		Task testTask = new Task(subject='sw test',status='Completed',accountid=tAcct.id);
		       	
    	try{
			insert testTask;
		}catch(DMLException d2){
			system.assert(false,'\n\nERROR INSERTING TEST TASK:'+d2.getDMLMessage(0));
		}
		
		//now check to see if the SWDate was updated
		Account checkAcct = [select id,name from Account where id=:tAcct.id];
		system.assert(checkAcct.Last_SW_Activity__c==Date.today(),'\n\nERROR: Date not updated correctly');
}

 

tgk1tgk1

Thanks Jim!  Really appreciate your help.  I updated the apex trigger and I just tried to compile the test class.  I'm getting this error for the test "Compile Error: Field is not writeable: Task.AccountId at line 20 column 81".

 

For the task the following field that wasn't included is the "Due Date" field. Any idea on why this won't compile??  Thanks again!

 

 

tgk1tgk1

I modified the class that you wrote and it compiles - but it's not running properly:

 

/**
 * Test Class for the LastSWDate Task Trigger
 * To do - If the subject of a completed task contains "SW", put the date of the completed task in the 
 * the "Last_SW_Activity__c" field on the account object
 * Created 8/30/2011
 * 
 */
@isTest
private class LastSWDateTest {

    static testMethod void myUnitTest() {
        //Setup
        Date lastSWDate = Date.newInstance(2009,01,01);//make this in the past to insure the test works correctly
        Account tAcct = new Account(name='Test Account',Last_SW_Activity__c=lastSWDate);//you might need to add more required fields to this
        try{
            insert tAcct;
        }catch(DMLException d1){
            system.assert(false,'\n\nERROR INSERTING TEST ACCOUNT:'+d1.getDMLMessage(0));
        }
        Task testTask = new Task(subject='sw test',status='Completed');
                
        try{
            insert testTask;
        }catch(DMLException d2){
            system.assert(false,'\n\nERROR INSERTING TEST TASK:'+d2.getDMLMessage(0));
        }
        
        //now check to see if the SWDate was updated
        Account checkAcct = [select id,name from Account where id=:tAcct.id];
        system.assert(checkAcct.Last_SW_Activity__c==Date.today(),'\n\nERROR: Date not updated correctly');
   }
}

 The test error says "  System.SObjectException: SObject row was retrieved via SOQL without querying the requested field: Acount.Last_SW_Activity__c"

 

Any idea?  Thanks!

JimRaeJimRae

Sorry about that, the task needs to reference the Whatid related to the Account, not the AccountID (that was the not writeable error), I fixed that. and the query for the checkacct was missing the field we were testing, so I fixed that.

 

/**
 * Test Class for the LastSWDate Task Trigger
 * To do - If the subject of a completed task contains "SW", put the date of the completed task in the 
 * the "Last_SW_Activity__c" field on the account object
 * Created 8/30/2011
 * 
 */
@isTest
private class LastSWDateTest {

    static testMethod void myUnitTest() {
        //Setup
        Date lastSWDate = Date.newInstance(2009,01,01);//make this in the past to insure the test works correctly
        Account tAcct = new Account(name='Test Account',Last_SW_Activity__c=lastSWDate);//you might need to add more required fields to this
        try{
            insert tAcct;
        }catch(DMLException d1){
            system.assert(false,'\n\nERROR INSERTING TEST ACCOUNT:'+d1.getDMLMessage(0));
        }
        Task testTask = new Task(subject='sw test',status='Completed',whatid=tAcct.id);
                
        try{
            insert testTask;
        }catch(DMLException d2){
            system.assert(false,'\n\nERROR INSERTING TEST TASK:'+d2.getDMLMessage(0));
        }
        
        //now check to see if the SWDate was updated
        Account checkAcct = [select id,name,Last_SW_Activity__c from Account where id=:tAcct.id];
        system.assert(checkAcct.Last_SW_Activity__c==Date.today(),'\n\nERROR: Date not updated correctly');
   }
}

 

tgk1tgk1

Your the man!  This is so close I can taste it...when I run the test it fails with this error:

 

Failure Message: "System.AssertException: Assertion Failed: ERROR: Date not updated correctly", Failure Stack Trace: "Class.LastSWDateTest.myUnitTest: line 30, column 9 External entry point"

 

 

Would it make a difference that the Last_SW_Activity__c field is a date/time field?

JimRaeJimRae

Yes, that would do it.  The system Date/Time method wouldn't work correctly, as it would always be a few seconds after the task was inserted.

 

system.assert(checkAcct.Last_SW_Activity__c > Datetime.now().addMinutes(-10),'\n\nERROR: Date not updated correctly');

This will test to see if the LastSw Activite date is greater than 10 minutes ago, you could tweak this if your test case is running too slow, but this should get it done.

This was selected as the best answer
tgk1tgk1

Awesome!  Thanks again Jim, have a great day.

logontokartiklogontokartik

The reason why you are getting error is because of the below line

 

Account checkAcct = [select id,name from Account where id=:tAcct.id];

 

 Please change it to include the Last_SW_Activity__c when you query. 

 

Account checkAcct = [select id,name, Last_SW_Activity__c from Account where id=:tAcct.id];

 

This will resolve the error you are getting, but I dont think your test is right. You are not establishing a relationship between a task and an account in your trigger.