+ Start a Discussion
CprocessingCprocessing 

Novice Question - APEX Test Help

Hi Guys,

 

I'm struggling to write an apex test class for my apex trigger. Please Bear in mind that this is the second thing i've ever written in APEX, however i do have other programming knowledge.

 

My Apex Trigger looks something like this:

 

trigger DisputeStatus on Dispute__c (before update) {

	// Get Trigger Object
	Dispute__c dispute = trigger.new[0];
	
	
	if((dispute.Un_Actioned_Conversations__c == 0) && (dispute.Resolved__c == true))
	{
		dispute.Status_of_Problem__c = 'Resolved';
		dispute.Resolved__c = true;
	} else if (dispute.Un_Actioned_Conversations__c > 0)
	{
		dispute.Status_of_Problem__c = 'Waiting for ACTION';
		dispute.Resolved__c = false;
	} else
	{
		dispute.Status_of_Problem__c = 'Waiting for RESPONSE';
		dispute.Resolved__c = false;
	}
}

 

Background information

 

An account object has these custom "Dispute" objects attached

 

A dispute object has custom "Conversation" objects attached

 

dispute.Un_Actioned_Conversations__c // is a roll up summary counting a boolean field in conversation 

 

However i have no idea how to write an APEX test class. I understand that it's essentially a unit test and should test the all the scope of the trigger. I've had a go, using tutorials, and produced the following code:

 

@isTest
private class testDisputeStatus {

    static testMethod void myUnitTest() {
        Dispute__c dispute = new Dispute__c();

		        
        dispute.Un_Actioned_Conversations__c = 0;
        dispute.Resolved__c = false;

		insert dispute;
		
		dispute.Un_Actioned_Conversations__c = 1;
		
		update dispute;
		
		dispute.Resolved__c = true;
		
		update dispute;
		
		dispute.Un_Actioned_Conversations__c = 0;
		
		update dispute;
        
    }}

 However all i've managed to produce is : 

Field is not writeable: Dispute__c.Un_Actioned_Conversations__c

 I appreciate i'm probably doing this completely wrong however being pointed in the right direction would be appreciated.

 

Any ideas?

 

Best Answer chosen by Admin (Salesforce Developers) 
MayTheForceBeWithYouMayTheForceBeWithYou

Cprocessing,

 

I'm afraid you spoke too soon in calling my response brilliant as I made a rookie mistake-you need to requery the record before running the assert statements as the in-memory variables are not updated when the database is updated (a little quirk in Salesforce). Thus, adding the SOQL query lines and updating the System.assertEquals parameters accordingly should do the trick. Try this code:

 

@isTest
private class testDisputeStatus {

    static testMethod void myUnitTest() {
    	
   	//Create Account
   	Account testAccount = new Account(Name = 'test');
   	
   	//Insert the record
   	insert testAccount;
    
        //Create Dispute, with required account
	Dispute__c testDispute = new Dispute__c(Account__c = testAccount.Id);

	//Insert the record, this does not fire the trigger	
	insert testDispute;

	//Set resolved field to true
	testDispute.Resolved__c = true;
	
	//Update record & fire trigger, this should cause the
	//first if statement code to run
	update testDispute;

	//Query the database to refresh our dispute record variable
	Dispute__c updatedDispute1 = [SELECT Id, Status_of_Problem__c FROM Dispute__c WHERE Id = :testDispute.Id];

	//Ensure the code fired properly
	System.assertEquals(updatedDispute1.Status_of_Problem__c, 'Resolved');

	//Set resolved field to false		        
	testDispute.Resolved__c = false;

	//Update record & fire trigger, this should cause the
	//'else' code to run
	update testDispute;

	//Query the database to refresh our dispute record variable
	Dispute__c updatedDispute2 = [SELECT Id, Status_of_Problem__c FROM Dispute__c WHERE Id = :testDispute.Id];

	//Ensure the code fired properly
	System.assertEquals(updatedDispute2.Status_of_Problem__c,'Waiting for RESPONSE');

	//Insert a new conversation that looks up to the 
	//dispute record; note-you might have some required fields
	//that must be set other than what I specify here
	Conversation__c testConvo = new Conversation__c(Dispute__c = testDispute.Id);
	
	//Insert the Conversation
	insert testConvo;

	//This will now cause the Un_Actioned_Conversations field in
	//testDispute to be 1; this may fire your trigger automatically
	//but just in case let's update the record to be sure it fires
	update testDispute;
 
	//Query the database to refresh our dispute record variable
	Dispute__c updatedDispute3 = [SELECT Id, Status_of_Problem__c FROM Dispute__c WHERE Id = :testDispute.Id];
      
	//Ensure the code fired properly
	System.assertEquals(updatedDispute3.Status_of_Problem__c,'Waiting for ACTION');
        
    }
}

 

All Answers

MayTheForceBeWithYouMayTheForceBeWithYou

Cprocessing,

 

Roll-up summary fields are read-only within Salesforce so that is why when you try to manually edit the field's value Salesforce gives you an error. Your test code will need to include creating a dispute record and then also creating a conversation record that looks up to that dispute record. Try something like the following:

 

@isTest
private class testDisputeStatus {

    static testMethod void myUnitTest() {
        
	Dispute__c testDispute = new Dispute__c();

	//Insert the record, this does not fire the trigger	
	insert testDispute;

	//Set resolved field to true
	testDispute.Resolved__c = true;

	//Update record & fire trigger, this should cause the
	//first if statement code to run
	update testDispute;

	//Ensure the code fired properly
	System.assertEquals(dispute.Status_of_Problem__c,'Resolved');

	//Set resolved field to false		        
	testDispute.Resolved__c = false;

	//Update record & fire trigger, this should cause the
	//'else' code to run
	update testDispute;

	//Ensure the code fired properly
	System.assertEquals(dispute.Status_of_Problem__c,'Waiting for RESPONSE');

	//Insert a new conversation that looks up to the 
	//dispute record; note-you might have some required fields
	//that must be set other than what I specify here
	Conversation__c testConvo = new Conversation__c(Dispute__c = testDispute.Id);
	insert testConvo;

	//This will now cause the Un_Actioned_Conversations field in
	//testDispute to be 1; this may fire your trigger automatically
	//but just in case let's update the record to be sure it fires
	update testDispute;
       
	//Ensure the code fired properly
	System.assertEquals(dispute.Status_of_Problem__c,'Waiting for ACTION');
        
    }
}

 

 

Hope that helps!

CprocessingCprocessing

First of all thanks for your brilliant response.

 

I've learnt more from your well commented code example then about 50 internet tutorials.

 

However i've hit another problem. I've now been able to add some code in to meet my required fields (no thanks to your example) however i now get the following error.

 

testDisputeStatus.myUnitTest

308.0

System.AssertException: Assertion Failed: Expected: null, Actual: Resolved

Class.testDisputeStatus.myUnitTest: line 55, column 2 External entry point

 The code now looks as follows..

 

@isTest
private class testDisputeStatus {

    static testMethod void myUnitTest() {
    	
   	//Create Account
   	Account testAccount = new Account(Name = 'test');
   	
   	//Insert the record
   	insert testAccount;
    
        //Create Dispute, with required account
	Dispute__c testDispute = new Dispute__c(Account__c = testAccount.Id);

	//Insert the record, this does not fire the trigger	
	insert testDispute;

	//Set resolved field to true
	testDispute.Resolved__c = true;
	
	//Update record & fire trigger, this should cause the
	//first if statement code to run
	update testDispute;

	//Ensure the code fired properly
	System.assertEquals(testDispute.Status_of_Problem__c, 'Resolved');

	//Set resolved field to false		        
	testDispute.Resolved__c = false;

	//Update record & fire trigger, this should cause the
	//'else' code to run
	update testDispute;

	//Ensure the code fired properly
	System.assertEquals(testDispute.Status_of_Problem__c,'Waiting for RESPONSE');

	//Insert a new conversation that looks up to the 
	//dispute record; note-you might have some required fields
	//that must be set other than what I specify here
	Conversation__c testConvo = new Conversation__c(Dispute__c = testDispute.Id);
	
	//Insert the Conversation
	insert testConvo;

	//This will now cause the Un_Actioned_Conversations field in
	//testDispute to be 1; this may fire your trigger automatically
	//but just in case let's update the record to be sure it fires
	update testDispute;
       
	//Ensure the code fired properly
	System.assertEquals(testDispute.Status_of_Problem__c,'Waiting for ACTION');
        
    }
}

 It's a bit confusing, as it's obviously looking for 'Resolved'...

 

Any Suggestions? 

MayTheForceBeWithYouMayTheForceBeWithYou

Cprocessing,

 

I'm afraid you spoke too soon in calling my response brilliant as I made a rookie mistake-you need to requery the record before running the assert statements as the in-memory variables are not updated when the database is updated (a little quirk in Salesforce). Thus, adding the SOQL query lines and updating the System.assertEquals parameters accordingly should do the trick. Try this code:

 

@isTest
private class testDisputeStatus {

    static testMethod void myUnitTest() {
    	
   	//Create Account
   	Account testAccount = new Account(Name = 'test');
   	
   	//Insert the record
   	insert testAccount;
    
        //Create Dispute, with required account
	Dispute__c testDispute = new Dispute__c(Account__c = testAccount.Id);

	//Insert the record, this does not fire the trigger	
	insert testDispute;

	//Set resolved field to true
	testDispute.Resolved__c = true;
	
	//Update record & fire trigger, this should cause the
	//first if statement code to run
	update testDispute;

	//Query the database to refresh our dispute record variable
	Dispute__c updatedDispute1 = [SELECT Id, Status_of_Problem__c FROM Dispute__c WHERE Id = :testDispute.Id];

	//Ensure the code fired properly
	System.assertEquals(updatedDispute1.Status_of_Problem__c, 'Resolved');

	//Set resolved field to false		        
	testDispute.Resolved__c = false;

	//Update record & fire trigger, this should cause the
	//'else' code to run
	update testDispute;

	//Query the database to refresh our dispute record variable
	Dispute__c updatedDispute2 = [SELECT Id, Status_of_Problem__c FROM Dispute__c WHERE Id = :testDispute.Id];

	//Ensure the code fired properly
	System.assertEquals(updatedDispute2.Status_of_Problem__c,'Waiting for RESPONSE');

	//Insert a new conversation that looks up to the 
	//dispute record; note-you might have some required fields
	//that must be set other than what I specify here
	Conversation__c testConvo = new Conversation__c(Dispute__c = testDispute.Id);
	
	//Insert the Conversation
	insert testConvo;

	//This will now cause the Un_Actioned_Conversations field in
	//testDispute to be 1; this may fire your trigger automatically
	//but just in case let's update the record to be sure it fires
	update testDispute;
 
	//Query the database to refresh our dispute record variable
	Dispute__c updatedDispute3 = [SELECT Id, Status_of_Problem__c FROM Dispute__c WHERE Id = :testDispute.Id];
      
	//Ensure the code fired properly
	System.assertEquals(updatedDispute3.Status_of_Problem__c,'Waiting for ACTION');
        
    }
}

 

This was selected as the best answer
CprocessingCprocessing

Hi,

 

That's the ticket, all done 100% coverage!

 

No worries, trust me i've honestly learnt more about Apex from you code than anywhere else. If only everybody commented as clearly.

 

Thanks for the help!! 

MayTheForceBeWithYouMayTheForceBeWithYou

No worries; I've received plenty of help from other developers on this site in the past so I'm happy to give back where I can.