Force.com Debug Log Parser

Kyle Peterson has released the Force.com Debug Log Parser, a nifty little .NET app for parsing the mess of a debug log you get from Salesforce when executing Apex code.   You can see a video demonstration here.

Great work, Kyle!

P.S. The comments to the post suggest an interest by Salesforce to include this into the IDE.  Hopefully that happens.  Until then, I’ll install this version and use it regularly.

Comments (1) comments feed

Summer 09 Landing Page

Salesforce has published information about their Summer 09 release.  The landing page has all the links you need to get feature details, release notes, etc.  There is lots of really nice stuff coming.

Go to http://www.salesforce.com/community/summer09/ to read up on what’s coming.

Comments (1) comments feed

Testing HTTP Callouts

When writing Apex Code, there are some things that simply cannot be tested, namely HTTP callouts.  The Intro to Apex Code Test Methods has one solution to testing as much of an HTTP callout as possible.  That is to break the HTTP callout into 3 methods: 1) Build Request, 2) Make Request, 3) Handle Response.  In the test method, you are only calling the Build Request and Handle Response methods.

I have another approach.  My main reason for not using the approach mentioned above is that I didn’t read that post until after I developed something.  However, my approach accomplishes the same thing, but also adds a variable to your class so that you can know whether or not a test is running.  Knowing this may be useful in other situations too.

Here’s is a class that uses my technique.

public class sample {

	// Static variable that assumes a test is not running
	public static boolean isApexTest = false;
	
	public String main(){
	    
	    // Do a whole bunch of stuff
	    
		// Build the http request
		Http h = new Http();
		HttpRequest req = new HttpRequest();
	    req.setEndpoint('http://local.yahooapis.com/MapsService/V1/geocode?appid=YD-9G7bey8_JXxQP6rxl.fBFGgCdNjoDMACQA--&street=701+First+Ave&city=Sunnyvale&state=CA'); 
	    req.setMethod('GET');
	    
		// Invoke web service call
		String result = '';
		if (!isApexTest){
			// Make a real callout since we are not running a test
			HttpResponse res = h.send(req);
			result = res.getBody();
		} else {
			// A test is running
			result = '<?xml version="1.0"?><ResultSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:yahoo:maps" xsi:schemaLocation="urn:yahoo:maps http://api.local.yahoo.com/MapsService/V1/GeocodeResponse.xsd"><Result precision="address"><Latitude>37.416397</Latitude><Longitude>-122.025055</Longitude><Address>701 1st Ave</Address><City>Sunnyvale</City><State>CA</State><Zip>94089-1019</Zip><Country>US</Country></Result></ResultSet>';
		}
			
		// Do whole bunch of stuff
	    
	    return result;	    
	}
	
	// Wrapper method for "main" that we will call in the Test Class
	public String mainForTest(){
		isApexTest = true;
		return main();
	}
}

I have a static variable called isApexTest that I set to false by default so the code assumes a test is not running.  For testing purposes, I created a “wrapper” method (called “mainForTest()”) that I will call in my test class in order to test the main() method. This wrapper method sets the isApexTest variable to true, calls the main() method and then passes back the result from the main() method. mainForTest() is merely a way to get the isApexTest variable set to true.

My test class is below.

@isTest 
private class sample_test {

    static testMethod void main_test() {
	 	
		// Establish sample class
		sample s = new sample();
		
		// Call the mainForTest wrapper method so we can set the variable indicating that a test is running
		String retVal = s.mainForTest();
	 	
	 	// Add asserts for validation
	 	String expectedResult = '<?xml version="1.0"?><ResultSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:yahoo:maps" xsi:schemaLocation="urn:yahoo:maps http://api.local.yahoo.com/MapsService/V1/GeocodeResponse.xsd"><Result precision="address"><Latitude>37.416397</Latitude><Longitude>-122.025055</Longitude><Address>701 1st Ave</Address><City>Sunnyvale</City><State>CA</State><Zip>94089-1019</Zip><Country>US</Country></Result></ResultSet>';
	 	System.assertEquals(retVal, expectedResult);
	 	
	 }
	 
}

In case you are wondering why I use a static variable for isApexTest instead of a class property, it is because I originally developed this technique to test an Apex Web Service. Since all web service methods are static, I couldn’t create an instance of a class to set the property to true and then call the web service method. Web service methods must be invoked directly and not through an instance of a class. That’s where the wrapper method idea came from.

Another approach than a wrapper method would be to have an input variable to my main() method that accepts true/false whether a test was running.  I did not go with this approach because I might have many methods performing callouts and I preferred to have 1 public variable accessible throughout the entire class than a local variable in each method. If I used a local variable, I would need to keep passing it around to other methods.

Comment with your thoughts and alternative approaches.

Comments (17) comments feed

Free AppExchange Apps (presentation from SD User Group)

I had the privilege of being asked to present to the San Diego Salesforce User Group this past Friday.  The topic for the day was Appexchange Applications, Tools, and Components that you can download for Free!

I presented on a number of Arrowpointe Products as well as some 3rd party ones that, over the years, I have come to really appreciate.  I included apps that are both free and ones I consider well worth the money.  The list is not exhaustive and there are lots of good candidates.  For 3rd party apps, I tried to pick ones that were useful to all Salesforce Customers and not ones that were focused on specific business processes or technologies to be integrated with.  That pares down the list quite a bit.

If you are interested, you can download my slides.  For each app I presented on, there are links on the slides to learn more about them.

Thank you San Diego User Group for being a great group to present to and I hope to make it down that way again soon!

Comments off comments feed

Set Defaults for Opportunity Contact Roles (when converting)

It’s always bugged me that the Primary flag and a Role are not set on Opportunity Contact Roles when converting a Lead.  After every convert, I manually set these.  Typically, I set the Role to “Decision Maker”and the Primary Flag to True.  I got sick of doing this manually, so I wrote a trigger for it and I am sharing it with you all.

Trigger

trigger Opportunities on Opportunity (after insert) {

	Opportunities o = new Opportunities();
	o.SetContactRoleDefaults(Trigger.new);
    
}

Class

public class Opportunities {

    // Default Constructor
    public Opportunities()
    {
    }
    
    // Sets default values on the Contact Role record created during Conversion. Called on AFTER INSERT
    public void SetContactRoleDefaults(Opportunity[] opptys) 
    {
    	/***************
        * Variables
        ***************/
		set<ID> set_opptyIDs = new set<ID>();
		
		/***************
        * Initial Loop
        ***************/
        // Get a set of the Opportunity IDs being affected.
		for(Opportunity o:opptys) { 
			set_opptyIDs.add(o.id);
		}
		
		/***************
        * Process Records
        ***************/
        // Update the Contact Role record to be Primary and the Decision Maker
        list<OpportunityContactRole> list_opptyContactRolesToUpdate = new list<OpportunityContactRole>();
		for(OpportunityContactRole ocr:[select Id,IsPrimary,Role from OpportunityContactRole where OpportunityId in :set_opptyIDs]) { 
			ocr.IsPrimary = true;
			ocr.Role = 'Decision Maker';
			list_opptyContactRolesToUpdate.add(ocr);
		}
		
		if (list_opptyContactRolesToUpdate.size() > 0) {
			update list_opptyContactRolesToUpdate;
		}
		
    }
}

Test Class

@isTest 
private class Opportunities_Test {

    static testMethod void SetContactRoleDefaults_Test() {
        
        // Create a Lead
        Lead l = new Lead();
        l.lastname = 'Lastname';
        l.firstname = 'FirstName';
        l.company = 'Company';
        insert l;
        
        // Convert the Lead
        Database.LeadConvert lc = new database.LeadConvert();
		lc.setLeadId(l.id);
		
		LeadStatus convertStatus = [Select Id, MasterLabel from LeadStatus where IsConverted=true limit 1];
		lc.setConvertedStatus(convertStatus.MasterLabel);
		
		Database.LeadConvertResult lcr = Database.convertLead(lc);
		System.assert(lcr.isSuccess());
		
		// Query Contact Role Records and Asserts all was set correctly.
		for (OpportunityContactRole ocr:[select Id,IsPrimary,Role from OpportunityContactRole where OpportunityId = :lcr.getOpportunityId()]) {
			system.AssertEquals('Decision Maker', ocr.Role);
			system.AssertEquals(true, ocr.IsPrimary);
		} 
        
    }
    
}

Comments (31) comments feed

Next entries » · « Previous entries