Andy in the Cloud

From BBC Basic to Force.com and beyond…


Leave a comment

Savings on Dreamforce 2013 Admission!

As a Force.com MVP I’ve been given a special discount code D13MVPREF for Dreamforce 2013 to pass on. Feel free to pass it around as well, there is no limit to how often it can be used to save  money on your entry to this amazing event!

Dreamforce.001

If your on the fence about Dreamforce 2013, I recommend it 110%, its a huge event and unlike smaller events, the educational cost benefit is very high. Since there are many many developer tracks, code review activities and training sessions.

There is so much content in fact, that an argument could be made that the more people you send the more benefit you get! Also there are many opportunities to discuss with fellow developers and Salesforce employees. In fact you’ll be hard pushed to attend the whole event without bumping shoulders with a Salesforce Product Manager!

If you need any more convincing head over to the official Dreamforce 2013 site!


3 Comments

Hidden Gem no longer Hidden! Database.Error.getFields

hiddengemA little while ago a developer I was working with found something undocumented in Apex. While it was a great find and very much what we needed at the time to achieve our goal to generically log errors from a Database.insert. Undocumented features can come back to bite you! For starters they are not supported and worse still can change without notice. I decided to raise a support case anyway, as it may have been a documentation oversight. The result is a few months later after a bit of testing, Salesforce have documented it and all is well! And whats more its available now!

This feature relates to an Apex class called Database.Error, used by the methods on the Database class. When performing DML operations (such as insert, update or delete for example) with a set of records the default behaviour is to fail the entire operation if any one of the records is in error .

In our case we wanted to allow valid records through and log errors for those that failed. Thus we passed false to the second parameter of the Database.insert method. The information we got back was useful but critically lacked the fields in error, leaving the user to decipher the field causing the error from the messages. The much needed getFields method returns a list of the field/s associated with the error message.

This method has now been documented, many thanks to Apex Product Manager Josh Kaplan and his team, enjoy!

List<Database.SaveResult> saveResults = Database.insert(recordsToInsert, false);
for(Database.SaveResult saveResult : saveResults)
{
    if(saveResult.isSuccess())
        continue;
    for(Database.Error err : saveResult.getErrors())
    {
        System.debug('The following error has occurred.');
        System.debug(err.getStatusCode() + ': ' + err.getMessage());
        System.debug('Fields in this error: ' + err.getFields());
    }
}


20 Comments

Code Coverage for WSDL2Apex Generated Classes

Force.com provides a means to generate Apex classes that allow the calling of a given Web Service as described by a WSDL (Web Service Definition Language). This tool is often referred to as the WSD2Apex tool. Despite not having any real “logic” in them, these classes also need code coverage in order to deploy to Production or include a Package.

While the tests for your Apex code that calls the Web Service indirectly ensures you obtain a certain amount of coverage of these classes, it may not be enough. Since you may only require use of a subset of the types and methods generated. The solution is often to comment out the bits not needed, however this is less than ideal if you plan on regenerating the Apex classes, when the Web Service is updated.

This short blog illustrates a way to generically cover the types and methods generated by the WSDL2Apex tool. Such that you don’t need to modify the generated code and can freely update it as desired, adding or removing types or methods in your test class accordingly. It utilises the UPS Street Address Web Service as per this Stack Exchange question, it requires a small tweak to the WSDL before doing so.

Step 1. Covering Generated Types. Each of the inner classes generated represents the data types from the WSDL (sometimes these are split into separate Apex classes). While they don’t have any methods in them, they do have static initialisation code. Constructing each of these classes will execute this logic and generate coverage.

For each of these in the generated class….

public class wwwUpsComXmlschemaXoltwsCommonV10 {
    public class TransactionReferenceType {
        public String CustomerContext;
        public String TransactionIdentifier;
        private String[] CustomerContext_type_info = new String[]{'CustomerContext','http://www.w3.org/2001/XMLSchema','string','0','1','false'};
        private String[] TransactionIdentifier_type_info = new String[]{'TransactionIdentifier','http://www.w3.org/2001/XMLSchema','string','0','1','false'};
        private String[] apex_schema_type_info = new String[]{'http://www.ups.com/XMLSchema/XOLTWS/Common/v1.0','true','false'};
        private String[] field_order_type_info = new String[]{'CustomerContext','TransactionIdentifier'};
    }

Create a test class and test method to cover the type inner classes, repeating line 6 for each.

@IsTest
private with sharing class wwwUpsComWsdlXoltwsXavV10Test
{
	private static testMethod void coverTypes()
	{
		new wwwUpsComXmlschemaXoltwsCommonV10.TransactionReferenceType();
	}
}

Step 2. Covering Generated Methods. Each of the methods on the Port inner class represents the operations described in the WSDL. Fortunately these methods do not care much about the data flowing in or out of them, which makes it easier to create a generic Web Service mock implementation.

For each of these in the generated class methods, observe the types used on lines 9 and 10.

public class wwwUpsComWsdlXoltwsXavV10 {
    public class XAVPort {
        public wwwUpsComXmlschemaXoltwsXavV10.XAVResponse_element ProcessXAV(
                wwwUpsComXmlschemaXoltwsCommonV10.RequestType Request,
                String RegionalRequestIndicator,
                String MaximumCandidateListSize,
                wwwUpsComXmlschemaXoltwsXavV10.AddressKeyFormatType AddressKeyFormat)
        {
            wwwUpsComXmlschemaXoltwsXavV10.XAVRequest_element request_x = new wwwUpsComXmlschemaXoltwsXavV10.XAVRequest_element();
            wwwUpsComXmlschemaXoltwsXavV10.XAVResponse_element response_x;
            // ... WSDL2Apex generated code removed for brevity ...
            return response_x;
        }
    }
}

Then create the following inner class in your test and repeating lines 11 and 12.

@IsTest
private with sharing class wwwUpsComWsdlXoltwsXavV10Test
{
	private class WebServiceMockImpl implements WebServiceMock
	{
		public void doInvoke(
			Object stub, Object request, Map<String, Object> response,
			String endpoint, String soapAction, String requestName,
			String responseNS, String responseName, String responseType)
		{
			if(request instanceof wwwUpsComXmlschemaXoltwsXavV10.XAVRequest_element)
				response.put('response_x', new wwwUpsComXmlschemaXoltwsXavV10.XAVResponse_element());
			return;
		}
	}
}

Create a test method to cover the generated methods, for each of the methods in generated code repeat line 6 for each. Note that you don’t need to worry about the values being provided to the methods, as the Web Service mock does nothing with them at all. Note that the test context still limits the number of callouts to 10 per test method, so you may need to split the method calls across two test methods.

@IsTest
private with sharing class wwwUpsComWsdlXoltwsXavV10Test
{
	private static testMethod void coverMethods()
	{
		new wwwUpsComWsdlXoltwsXavV10.XAVPort().ProcessXAV(null, null, null, null);
	}
}

Summary. If you want to see a full example of this type of test check out this test class based on the Salesforce Metadata API Web Service. This approach may not be for everyone, certainly if you are already covering a large portion of the generated code or prefer to just delete / comment out the code you don’t need it. However if your providing some kind of connector library or you just want to retain the ability to upgrade the Web Service more easily, or your just determined to keep your 100% code coverage, this might help!