So SalesforceDX is good for many things but this particular blog post is going to be around how it provides easy access to something which is otherwise hard or cumbersome to get at. Like Apex class test coverage. It’s available through other means such as the UI and the tooling api but there it takes manual work (clicking) or requires additional plumbing to set up and extract. With SalesforceDX it’s surprisingly easy.
As opposed to popular belief SalesforceDX may be used with any org and not just the scratch orgs that SalesforceDX affords for development. Connecting to any org is as simple as using the Force to do the OAuth dance:
$ sfdx force:auth:web:login
For additional points you can give the org connection an alias for easy reference (using –setalias) and specify the login URL if required (using –instanceurl) i.e. if you’re adding a sandbox.
$ sfdx force:auth:web:login --setalias MyOrg --instanceurl https://test.salesforce.com
Once you have the org connection you can use force:apex:test:run to run tests and force:apex:test:report to – surprise – return the test report.
$ sfdx force:apex:test:run -u mheisterberg@example.com.appdev Run "sfdx force:apex:test:report -i 7076E00000Uo5sc -u mheisterberg@example.com.appdev" to retrieve test results. $ sfdx force:apex:test:report -i 7076E00000Uo5sc -u mheisterberg@example.com.appdev === Test Results TEST NAME OUTCOME MESSAGE RUNTIME (MS) ────────────────────────────────────────────────────────────────── ─────── ─────── ──────────── ChangePasswordControllerTest.testChangePasswordController Pass 11 AccountTriggerHandlerTest.testSetAccountOwner Pass 3623 AccountTriggerHandlerTest.testSetContactId Pass 114 AccountTriggerHandlerTest.testSetLowecaseEmail Pass 215 AccountTriggerHandlerTest.testSetPCAK Pass 83 AccountTriggerHandlerTest.testValidateEmailUniquenessNegative Pass 42 AccountTriggerHandlerTest.testValidateEmailUniquenessPositive Pass 80 AddressesListRestTest.testGetAddressesList Pass 11097 AddressRestTest.testDeleteAddress Pass 1388 AddressRestTest.testGetAddress Pass 753 AddressRestTest.testPostAddress Pass 734 AddressRestTest.testPutAddress Pass 731 ConsentRestTest.testGetConsent Pass 959 ConsentRestTest.testPostConsent Pass 768 ConsentRestTest.testPutConsent Pass 975 ConsentsListRestTest.testGetConsensList Pass 3761 ConsumerRestTest.testGetConsumer Pass 1004 ConsumerRestTest.testPostConsumer Pass 988 MarketRelationTriggerHandlerTest.testBehavior Pass 8 ProfileRestTest.testDeleteProfile Pass 1071 ProfileRestTest.testGetProfile Pass 710 ProfileRestTest.testPostProfile Pass 739 ProfileRestTest.testPutProfile Pass 679 ProfilesListRestTest.testGetProfilesList Pass 921 ForgotPasswordControllerTest.testForgotPasswordController Pass 29 MyProfilePageControllerTest.testSave Pass 258 SiteLoginControllerTest.testSiteLoginController Pass 17 SiteRegisterControllerTest.testRegistration Pass 16 === Test Summary NAME VALUE ─────────────────── ───────────────────────────── Outcome Passed Tests Ran 28 Passing 28 Failing 0 Skipped 0 Pass Rate 100% Fail Rate 0% Test Start Time Apr 13, 2018 10:18 AM Test Execution Time 31774 ms Test Total Time 31774 ms Command Time 50941 ms Hostname https://cs85.salesforce.com Org Id 00D6E0000008eojUAA Username mheisterberg@example.com.appdev Test Run Id 7076E00000Uo5sc User Id 0051r0000087iv9AAA
It’s pretty nifty huh!?
Again for added points add –json to the test report command to get the data back in JSON. And if you already have something that accepts test coverage data from say JUnit you can just add “–resultformat junit” and boom! You’ll get the test report in JUnit XML format. But everything started with me wanting to retrieve code coverage data and that hasn’t been part of the output so far. But again SalesforceDX to the rescue… Just add –codecoverage and you’ll receive code coverage percentages as well as part of the report.
$ sfdx force:apex:test:report -i 7076E00000Uo5sc -u mheisterberg@example.com.appdev -c == Apex Code Coverage ID NAME % COVERED UNCOVERED LINES ────────────────── ───────────────────────────────── ────────────────── ──────────────────────────────────────────────────────────────────── 01p6E000000aSHvQAM SiteLoginController 100% 01p6E000000aSHxQAM SiteRegisterController 81.48148148148148% 39,40,43,44,45 01p6E000000aSHzQAM ChangePasswordController 100% 01p6E000000aSI1QAM ForgotPasswordController 88.88888888888889% 15 01p6E000000aSI3QAM MyProfilePageController 87.5% 21,37,38 01p6E000000brQtQAI AccountTriggerHandler 95% 61,63,66,181 01p6E000000cBdhQAE MarketRelationTriggerHandler 78% 38,40,41,42 01p6E000000csObQAI Wrappers 98% 5 01p6E000000aIXsQAM ConsentRest 79% 35,36,54,55,67,69,70,88,89,104,105,106,119,121,125 01p6E000000ak0yQAA SegmentBuilder 100% 01q6E0000004xLIQAY AccountTrigger 100% 01q6E0000004zB0QAI MarketRelationTrigger 80% 13 01p6E000000aUJVQA2 UserBuilder 100% 01p6E000000aJjqQAE ConsentsListRest 94.11764705882352% 48 01p6E000000cnhQQAQ AddressRest 78% 35,36,60,68,70,92,93,110,111,112,126,128,132,149,150,162,164,165 01p6E000000caCxQAI ConsumerRest 84% 17,18,27,28,49,50,51,111,120,146,148,149,159,220,222,225,284,290,297 01p6E000000aIXxQAM ProfileRest 76% 27,28,49,57,59,78,79,91,93,94,111,112,127,128,129,141,143,147 01p6E000000aJjWQAU ProfilesListRest 94.11764705882352% 41 01p6E000000cr6iQAA AddressesListRest 83.33333333333334% 39,52,54 === Test Results <snipped>
Combine that with –json and you have the foundation for automating this. So sweet. You could even write a little script to output this any way you like.
Happy scripting…
How to get the job id here sfdx force:apex:test:report -i 7076E00000Uo5sc -u mheisterberg@example.com.appdev -c?
LikeLike
The job ID is in the command you issue…
LikeLike
You didn’t answer the question here. The Job ID comes from the output of the previous command. The SFDC documentation makes it seem like it is returned directly (and easily) from the previous command, but in reality it comes as part of whatever larger output, and you are required to parse it out using whatever tooling you have available (sed, jq, etc.).
LikeLike