Because of Tolerado, I came to know about “Apex Programming WSDL” given by Salesforce. Apex WSDL on a high level gives web service APIs for
running apex tests
executeAnonymous code
compiling classes and triggers.
How to download this WSDL ?
Apex programming WSDL can be downloaded from “Setup” area of your Salesforce org. Just land on “App Setup > Develop > API” page. Instructions to download are shown below.
Integrating with “Apex Programming WSDL” !
One can compile/consume this WSDL in various programming languages like Java/PHP/.NET/etc. Post compilation, one can easily create mashup applications to behave like mini Cruise Control for Apex, those that can run nightly tests for your Salesforce Org etc. Only problem is those application needs to be hosted and maintained by one, not really on CLOUD unless one is developing one
Compiling “Apex WSDL” to generate Apex code stubs (WSDL > Apex)
Fortunately, one can also generate Apex code stubs for a given WSDL i.e. force.com platform gives you an option to do “WSDL > Apex” compilation.
Using this feature, we can bring the who bunch of web service exposed by “Apex WSDL” to Apex code directly.
So, lets hit the button showed in above screenshot i.e. “Generate from WSDL” and specify the downloaded “apex.wsdl” file, here, as shown below.
In next step, you will be asked to give a good name to the generated Apex class, by default it will come with something like “soapSforceCom200608Apex”. Detailed instructions shown below.
Next, you should see screen like following, giving you the link to the newly generated/compiled Apex class from “Apex WSDL”
Next, we will see how to invoke Apex WSDL web services from Apex code directly.
Invoke Apex WSDL web services from Apex Code
In this section I am assuming you have already generated “ApexStub” class by compiling Apex WSDL, as described above.
Step 1 – Know your web service end point !
As we are going to make web service calls from Apex code, we need to whitelist the web service endpoints first. To know your web service endpoint, there are two ways i.e.
1. Check location attribute of <soap:address location=”https://….”> in Apex WSDL file, it should have something like this. So for my org the web service endpoint to white list is “https://ap1-api.salesforce.com/services/Soap/s/20.0”
<soap:address location="https://ap1-api.salesforce.com/services/Soap/s/20.0"/>
2. You can also check your endpoint directly in the ApexStub class. “ApexStub.Apex.endpoint_x” property points to the web service endpoint.
Step 2 – Whitelist the web service end point
To white list, goto “Setup > Administration Setup > Security Controls > Remote Site Settings” and create a “New Remote Site” using the domain details from endpoint captured in steps above. Make sure remote site url is as per your SFDC org, my org is on node “ap1”, yours can be different i.e. on NA1 etc. My security settings are shown below.
Step 3 – Coding time, make the web service call !
Out of all web service calls given by Apex WSDL, most interesting for me is runTests(). This allows one to run tests on either a single, bunch or all apex classes in sfdc org.
Run All Tests Sample
Here is the sample code that uses the “ApexStub” class generated above to run all tests in the org.
ApexStub.Apex ap = new ApexStub.Apex();
ap.SessionHeader = new ApexStub.SessionHeader_element ();
// This is important, give session id, to let the call work.
ap.SessionHeader.sessionId = UserInfo.getSessionId();
ApexStub.RunTestsRequest rtr = new ApexStub.RunTestsRequest();
// Run All Tests
rtr.allTests = true;
rtr.Namespace = '';
// Execute the Tests
ApexStub.RunTestsResult testResults = ap.runTests(rtr);
System.debug("Failures >" + testResults.numFailures);
Running test on Single or bunch of classes
// You can also specify single class in this array
String[] classNames = new String [] {'TestFeature1', 'TestFeature2'};
// or specify package or org wide
// namespace here
String namespace = '';
ApexStub.Apex ap = new ApexStub.Apex();
ap.SessionHeader = new ApexStub.SessionHeader_element ();
ap.SessionHeader.sessionId = UserInfo.getSessionId();
ApexStub.RunTestsRequest rtr = new ApexStub.RunTestsRequest();
rtr.classes = classNames;
rtr.allTests = false;
rtr.Namespace = namespace;
ApexStub.RunTestsResult results = ap.runTests(rtr);
For more details on how to,
Making Apex WSDL calls from Apex – Limitations !!
As we are making web service callouts from Apex, all the governor limits imposed on web service callouts are applicable here too. For ex.
Total request time for all callouts (HTTP requests or Web services calls) in a single unit of work is 120 secs
Maximum size of callout request or response (HTTP request or Web services call) is 3 MB
Out of these two only the first one limits us most from doing anything super creative from Apex. So you can’t run all/single/bunch tests, if they consume more than 120 secs to complete. This is pretty easily possible with an org with decent number of apex classes.
So one can’t go straight forward and do anything with Apex WSDL calls.
Creating a Junit like Test Suite using Apex WSDL.
Junit is a unit testing framework in Java. Many bits and pieces of Apex TestCase class are inspired from this framework itself.
A nice feature that’s given by Junit is ability to create TestSuites. A TestSuite
is a Composite
of Tests. It runs a collection of test cases. The beauty of test suites is you can create small suite of tests per feature or module of your org, this suite will have test classes for the feature/module only. So when you change something, its really not required to run all the tests, you can just run suite and see if everything for the feature is stable.
Apex Test Suites & ApexClass Sobject !
As of now, Apex doesn’t offers this feature. But we can run tests on single class as described above, so why don’t we use this feature to create test suites in Apex. But for that we need access to Apex Classes available in the org.
Good news !!! Salesforce schema already has an Sobject called “ApexClass”, this sobject keeps information about all the classes in a SFDC org. One can query this Sobject for details like ClassName, Namespace, Body and length etc.
So, to create Test Suite an rough idea could be to
Create a “TestSuite” and “TestSuiteClass” custom Sobject. “TestSuiteClass” will keep apex class name and namespace, because we can’t lookup or master details to ApexClass object. Test Suite Class will master detail on “TestSuite”.
Create a Visualforce page/apex controller, that queries ApexClass sobject and presents a list of Apex classes to end user to select. These selected Apex classes then can be used to create a TestSuite/TestSuiteClass records.
Now having this TestSuite and ApexStub class we can execute it in many ways, a slight challenge will be to hack around the governor limits imposed. For ex. we can create another Visualforce/Apex page to run tests available in the TestSuite.
Also by using TestSuite and ApexStub class, we can also create applications that tells coverage etc. As RunTestsResult returned after running tests, have fine details about that too.
Test Suite as a Salesforce App – Your views
Let me know what do you feel about this TestSuite concept, if its really worth moving forward like this. If you have some ideas and good feeling about it, we can join our efforts to create an opensource project for this.
Getting Test Suite natively in Force.com Platform – Idea exchange !
I posting TestSuite as an idea on Salesforce Idea Exchange too, to get this feature natively in platform itself. Here is the link to that idea : https://sites.secure.force.com/success/ideaView?c=09a30000000D9xtAAC&id=08730000000KPkXAAW
Please promote it to make the platform better.
Comments (6)
Anonymoussays:
April 7, 2011 at 5:03 amhiWhile generating the apex stub from the apex.wsdl i m getting he error:could not determine namespace bound to element prefix xsd (position: TEXT seen …”qualified” targetNamespace=”http://soap.sforce.com/2006/08/apex”>..can you please let me know why this error is coming?do i need to change in the generated wsdl.ThanksAmar
Anonymoussays:
April 7, 2011 at 6:49 amHey Amar,I just retried the steps and generated Apex stubs from apex.wsdl, it worked in one shot. If you need a copy of the generated stub, I uploaded it to my dropbox public folder here : http://dl.dropbox.com/u/1162324/abhinav.ApexStubForAmar.clsThanks,Abhinav
Anonymoussays:
September 20, 2011 at 10:38 amHi Abhinav,Can we do a scenario wherein when an opportunity gets closed, I need to push the opportunity and associated Account to another Sandbox and create a new contact and account there. Please do let me know. I am kind of stuck in terms of finding a solution for this.
Anonymoussays:
September 20, 2011 at 10:53 amHi @BigShow, Please give me more context about the problem. Are you trying to connect to other sandbox using Apex/Visualforce only ?
Anonymoussays:
September 21, 2011 at 4:37 amHi Abhinav,I am using only Apex. Here is more detailed requirement:Org A: User selects an opportunity and closes it. Stage is “Closed”. Now on update of the Opp record, I need to trigger a call to Salesforce Org B with Opportunity record, associated Account record and Contact RecordOrg B: Apex class in Org B should receive the record mentioned above and create new Account and Contact in Org B after applying some business logic. I tried importing Enterprise and Partner WSDL and I get some XSD errors. Please do provide your thoughts
Anonymoussays:
September 22, 2011 at 3:04 amI believe the cleanest way to do this is use “Salesforce to Salesforce”. Please read this article for full details : http://wiki.developerforce.com/index.php/An_Introduction_to_Salesforce_to_Salesforce