Andy in the Cloud

From BBC Basic to Force.com and beyond…


19 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!