+ Start a Discussion
dmchengdmcheng 

Need clarification on writing test methods for VF and controller extensions

I need a basic understanding of how to write test code for a controller extension with a VF page, and I'm just not getting it from p.72-74 of the Pages Developer guide.

I've written a VF page and extension to override the Lead Convert button.  The extension creates a contact and account as normal, but can create more than one opp based on a custom field's values.

 

[Here's the contoller extension] public class LeadExtension { private final ApexPages.StandardController jsLeadController; public LeadExtension(ApexPages.StandardController stdController) { jsLeadController = stdController; } public PageReference autoRun() { // //Code here to create contact and account, then create one or more opps as needed, then return to //the standard "conversion successful" page // } } [Here's the VF page, named LeadConversion] <apex:page standardController="Lead" extensions="LeadExtension" action="{!autoRun}"> </apex:page>

 

* Do I first set up a lead record with test values as I would do in a typical unit test?

* How do I invoke the VF page to kick off the autorun extension?  Do I just execute the code below?  (The VF page is named LeadConversion.)  Do I need to pass the Lead ID somehow?

 

//Create a reference to the VF page PageReference pageRef = Page.LeadConversion; Test.setCurrentPageReference(pageRef);

 

 Thanks

David

 

 

 

Best Answer chosen by Admin (Salesforce Developers) 
patrospatros

I tested this out (because I have never run into this situation and was curious too) - it turns out that in your tests you do have to explicitly call the method you assign as an action to your page. Simply adding a PageReference to a VF page with an action assigned and expecting it to fire in the test won't happen.

 

Here's the sample code I used to try this out (using a Contact as standardController):

 

public class DummyController {

public Contact contact { get; set; }

public DummyController(ApexPages.StandardController controller) {
contact = (Contact)controller.getRecord();
contact.FirstName = 'Test';
contact.LastName = 'Test';
}

public void AddContact() {
upsert contact;
}

public void RemoveContact() {
delete contact;
}

public static testMethod void TestDummyController() {

// define Page parameters
// Even though I'm assigning a PageReference to a page that has an "action", it will be ignored in the context of the testMethod...
PageReference pageRef = Page.DummyPage;
Test.setCurrentPageReference(pageRef);

// test with new Contact
DummyController controller = new DummyController(new ApexPages.StandardController(new Contact()));
// comment out the next line to make the assertion two lines down fail...
controller.AddContact();
System.assertNotEquals(controller.contact.Id, null, 'AddContact() action on DummyPage did not fire automatically. You must explicitly call AddContact() in your test');
controller.RemoveContact();
}
}

VF PAGE...
<apex:page standardController="Contact" extensions="DummyController" action="!{AddContact}">
</apex:page>

 

 

 

All Answers

patrospatros

Hi David,

 

You're on the right track. Couple of things:

  1. You do need to run all of your tests within a public static method marked as a testMethod. I assume your code snippet below is excluding this?
  2. You are correct about generating a lead as part of your tests, as it gives you an object to work with in the context of your tests.
  3. You are also correct about the PageReference code listed below. This gives the test context.You could pass the lead ID here, depending on what you wanted to test.
  4. To actually test your controller (or extension, in this case), you need to create an instance of it after declaring all the PageReference bits. This was a little mind-boggling for me the first time, but you're literally creating an instance of the controller and your test executes as though a user were interacting with your VF page.

Here's a snip of code to help out - I'll let you fill in the blanks:

 

 

public static testMethod void LeadExtensionTest() { // create a new lead... Lead lead = new Lead(); // ...set additional fields... insert lead; //Create a reference to the VF page PageReference pageRef = Page.LeadConversion; Test.setCurrentPageReference(pageRef); // if you wanted to test an existing lead, use the line below (assuming your extension expects the ID param to be set) // ApexPages.currentPage().getParameters().put('id', lead.Id); // create an instance of your extension // this assumes a new Lead... LeadExtension extension = new LeadExtension(new ApexPages.StandardController(new Lead())); // if you wanted to test an existing lead, use the line below... // LeadExtension extension = new LeadExtension(new ApexPages.StandardController(lead)); // ... start calling methods to exercise your code ... // tear down objects created in the test delete lead; }

 

 Hope this helps!

 

 

 

 

dmchengdmcheng

Thanks patros, this was very helpful.  Yes I have most of the test code written out as you show.

 

One thing I still don't understand - what's the code syntax to accept parameters within the extension?  Is the "property" item that's referred to on page 370 of the Pages Dev guide?  So would my ID parameter look like this in the extension?

 

public ID leadID {get; set;};

 

I'm not finding any examples of controllers that accept parameters (the way I understand them at least).

patrospatros

You could do something like:

 

LeadExtension extension = new LeadExtension(...); extension.leadID = 'ABC123';

Or, you could create a public setter method to set the lead ID:

 

public LeadExtension() { // other stuff... public ID leadID { get; set; } public ID getLeadID() { return leadID; } public void setLeadID(ID value) { leadID = value } } ... in your test ... LeadExtension extension = new LeadExtension(...); extension.setLeadID('ABC123');

 Either way should work, although I have had some intermittent (and unexplainable) issues with the first approach, so the setter method approach is probably your safest bet.

 

If anyone else in SalesforceCommunityLand can shed some light on when to use a { get; set; } vs. getter and setter method, I would defintely be all-ears.

 

 

 

dmchengdmcheng

Unfortunately it's still not working for me.

 

Here's the extension:

 

public class LeadExtension { private final ApexPages.StandardController jsLeadController; public LeadExtension(ApexPages.StandardController stdController) { jsLeadController = stdController; } // Code we will invoke on page load. public PageReference autoRun() { //get the lead we are converting. Lead thisLead = [select Id, Assistance_Type__c, CreatedDate from Lead where Id = :jsLeadController.getId()]; Database.LeadConvert lc = new database.LeadConvert(); Opportunity[] opps = new List<Opportunity>(); Contact_Opportunity_Role__c[] roles = new List<Contact_Opportunity_Role__c>(); lc.setLeadId(thisLead.Id); lc.setConvertedStatus('Converted'); lc.setDoNotCreateOpportunity(True); Database.LeadConvertResult lcr = Database.convertLead(lc); //Create one or more opportunities here.

return jsLeadController.view().setRedirect(true); } }

 

Here's the test code.  I have it in a separate class along with other test methods.

 

static testmethod void testLeadExtension() { Lead newLead = new Lead(Firstname = 'Apex', LastName = 'Tester', Company = 'Apex Test Corp', Status = 'Raw', Assistance_Type__c = 'JS Ventures; JS TL Advisors; JS Inclusion', LeadSource = 'Web'); insert newLead; Id leadId = newLead.Id; //Create a reference to the VF page PageReference pageRef = Page.LeadConversion; Test.setCurrentPageReference(pageRef); ApexPages.currentPage().getParameters().put('id', leadId); //Create an instance of the controller extension LeadExtension leadExt = new LeadExtension(new ApexPages.StandardController(newLead)); newLead = [select Id, IsConverted, ConvertedAccountId, ConvertedContactId from Lead where Id=:leadId]; Account acct = [select Id from Account where Id = :newLead.ConvertedAccountId]; Contact con = [select Id from Contact where Id = :newLead.ConvertedContactId]; }

 

 

 

 When I do a system debug on newLead.IsConverted at the end of the method, the value is False.

 

patrospatros

Looks like you extension might have more than you need in it. Try this:

 

public class LeadExtension { // this is the "primary" record that this extension will do work on private final Lead lead; // the constructor can get you the "primary" record via the controller passed in public LeadExtension(ApexPages.StandardController stdController) { lead = stdController.getRecord(); Database.LeadConvert lc = new database.LeadConvert(); lc.setLeadId(lead.Id); lc.setConvertedStatus('Converted'); lc.setDoNotCreateOpportunity(True); Database.LeadConvertResult lcr = Database.convertLead(lc); } public static void testMethod testLeadExtension() { Lead newLead = new Lead(Firstname = 'Apex', LastName = 'Tester', Company = 'Apex Test Corp', Status = 'Raw', Assistance_Type__c = 'JS Ventures; JS TL Advisors; JS Inclusion', LeadSource = 'Web'); insert newLead; //Create a reference to the VF page PageReference pageRef = Page.LeadConversion; Test.setCurrentPageReference(pageRef); ApexPages.currentPage().getParameters().put('id', newLead.Id); //Create an instance of the controller extension LeadExtension leadExt = new LeadExtension(new ApexPages.StandardController(newLead)); } }

 

 

 

dmchengdmcheng

Since I'm invoking the extension from a VF page that overrides the Lead Convert button, don't I need the Autorun coding in the extension?

 

VF page:

 

<apex:page standardController="Lead" extensions="LeadExtension" action="{!autoRun}"> <apex:outputText >Please wait ... lead conversion in progress ...</apex:outputText> </apex:page>

 

 

 

patrospatros

I tested this out (because I have never run into this situation and was curious too) - it turns out that in your tests you do have to explicitly call the method you assign as an action to your page. Simply adding a PageReference to a VF page with an action assigned and expecting it to fire in the test won't happen.

 

Here's the sample code I used to try this out (using a Contact as standardController):

 

public class DummyController {

public Contact contact { get; set; }

public DummyController(ApexPages.StandardController controller) {
contact = (Contact)controller.getRecord();
contact.FirstName = 'Test';
contact.LastName = 'Test';
}

public void AddContact() {
upsert contact;
}

public void RemoveContact() {
delete contact;
}

public static testMethod void TestDummyController() {

// define Page parameters
// Even though I'm assigning a PageReference to a page that has an "action", it will be ignored in the context of the testMethod...
PageReference pageRef = Page.DummyPage;
Test.setCurrentPageReference(pageRef);

// test with new Contact
DummyController controller = new DummyController(new ApexPages.StandardController(new Contact()));
// comment out the next line to make the assertion two lines down fail...
controller.AddContact();
System.assertNotEquals(controller.contact.Id, null, 'AddContact() action on DummyPage did not fire automatically. You must explicitly call AddContact() in your test');
controller.RemoveContact();
}
}

VF PAGE...
<apex:page standardController="Contact" extensions="DummyController" action="!{AddContact}">
</apex:page>

 

 

 

This was selected as the best answer
dmchengdmcheng

That was it, thanks Patros!!

 

for those who are interested, here's my final test code:

 

static testmethod void testLeadExtension() { Lead newLead = new Lead(Firstname = 'Apex', LastName = 'Tester', Company = 'Apex Test Corp', Status = 'Raw', Assistance_Type__c = 'Alpha; Bravo; Charlie', LeadSource = 'Web'); insert newLead; Id leadId = newLead.Id; //Create a reference to the VF page PageReference pageRef = Page.LeadConversion; Test.setCurrentPageReference(pageRef); //Create an instance of the controller extension and call the autoRun method. //autoRun must be called explicitly even though it is "autoRun". LeadExtension leadExt = new LeadExtension(new ApexPages.StandardController(newLead)); leadExt.autoRun(); //Retrieve the converted Lead info and the opps and roles. newLead = [select Id, IsConverted, ConvertedAccountId, ConvertedContactId from Lead where Id = :leadId]; Account acct = [select Id from Account where Id = :newLead.ConvertedAccountId]; Contact con = [select Id from Contact where Id = :newLead.ConvertedContactId]; Opportunity[] opps = [select Id from Opportunity where AccountId = :acct.Id]; Contact_Opportunity_Role__c[] roles = [select Id from Contact_Opportunity_Role__c where Contact__c = :con.Id]; //check that 3 opps and 3 roles were created. system.assertEquals(opps.size(), 3); system.assertEquals(roles.size(), 3); }