ApexTestQueueItem

Represents a single Apex class in the Apex job queue.

Version 

Introduced in API version 23.0.

Supported SOAP API Calls 

create(), describeSObjects(), query(), retrieve(), update(), upsert()

Supported REST API Methods 

GET, HEAD, PATCH, POST, Query

Fields 

ApexClassId 

  • Type: reference

  • Required: No

  • Properties: Create, Filter, Group, Nillable, Sort

  • Description: The Apex class whose tests are to be executed.

This field can’t be updated.

  • Relationship name: ApexClass
  • Relationship type: relationship
  • Refers to: ApexClass

ExtendedStatus 

  • Type: string

  • Required: No

  • Properties: Filter, Nillable, Sort

  • Description: The pass rate of the test run.

For example: “(4/6)”. This means that four out of a total of six tests passed.

If the class fails to execute, this field contains the cause of the failure.

ParentJobId 

  • Type: reference

  • Required: No

  • Properties: Filter, Group, Nillable, Sort

  • Description: Read-only. Points to the AsyncApexJob that represents the entire test run.

If you insert multiple Apex test queue items in a single bulk operation, the queue items will share the same parent job. This means that a test run can consist of the execution of the tests of several classes if all the test queue items are inserted in the same bulk operation.

  • Relationship name: ParentJobId
  • Relationship type: relationship
  • Refers to: AsyncApexJob

ShouldSkipCodeCoverage 

  • Type: boolean

  • Required: No

  • Properties: Create, Defaulted on create, Filter, Group, Sort, Update

  • Introduced: API version 43.0

  • Description: Indicates whether to opt out of collecting code coverage information during Apex test runs.

  • Default value: false

Status 

  • Type: picklist

  • Required: No

  • Properties: Filter, Group, Restricted picklist, Sort, Update

  • Description: The status of the test.

To abort a class that is in the Apex job queue, perform an update operation on the ApexTestQueueItem object and set its Status field to Aborted.

  • Possible values:

    • Queued — Queued

    • Processing — Processing

    • Aborted — Aborted

    • Completed — Completed

    • Failed — Failed

    • Preparing — Preparing

    • Holding — Holding

TestRunResultId 

  • Type: reference

  • Required: No

  • Properties: Filter, Group, Nillable, Sort

  • Introduced: API version 37.0

  • Relationship name: TestRunResultId

  • Relationship type: relationship

  • Refers to: ApexTestRunResult

Usage 

Insert an ApexTestQueueItem object to place its corresponding Apex class in the Apex job queue for execution. The Apex job executes the test methods in the class.

The example RunTestListener.java class subscribes to the TestResult system topic and prints out the test results using ApexTestQueueItem and ApexTestResult. The example makes these assumptions:

  • You have already set up a Java client application for Streaming API. This example uses the org.cometd.client.BayeuxClient created in the Java Client code example in the Streaming API Developer Guide.
  • You have a logged in com.sforce.soap.tooling.SoapConnection. For examples, see the SOAP API Developer Guide.
  • The logged-in user has the View All Data permission to subscribe to the TestResult system topic, /systemTopic/TestResult.

Instead of Streaming API, you can use Pub/Sub API to subscribe to events. Based on gRPC API and HTTP/2, Pub/Sub API delivers binary event messages in the Apache Avro format and is more efficient than Streaming API. See the Pub/Sub API Documentation.

Note

As an alternative to using ApexTestQueueItem, you can run test methods using the Salesforce CLI commands. See Run Apex Tests in the Salesforce DX Developer Guide.

The RunTestListener.java class must be instantiated after the Streaming API handshake. For example:

1SoapConnection toolingConn; //Already set and logged in
2BayeuxClient client; //Already set and logged in
3
4//Listen on the handshake event 
5boolean handshaken = client.waitFor(10 * 1000, BayeuxClient.State.CONNECTED); 
6if (!handshaken) {
7   System.out.println("Failed to handshake: " + client); 
8   System.exit(1); 
9} 
10final RunTestListener = null; 
11client.getChannel(Channel.META_SUBSCRIBE).addListener( 
12   new ClientSessionChannel.MessageListener() { 
13      public void onMessage(ClientSessionChannel channel, Message message) { 
14         boolean success = message.isSuccessful(); 
15         if (success) { 
16            //Replace with your own classes and suites
17            String apexTestClassId1 = "01pD00000007M0CIAU"; 
18            String apexTestClassId2 = "01pD00000007NqtIAE";
19            String apexTestSuiteId1 = "05FD00000004CDBMA2";
20            String apexTestClassName1 = "Test_MyClass";
21            String apexTestSuiteName1 = "TestSuite_MySuite";
22            listener.runTests(new String[]{apexTestClassId1, apexTestClassId2},
23               new String[]{apexTestSuiteId1}, 1, new String[]{apexTestClassName1},
24               new String[]{apexTestSuiteName1});
25         }
26      }
27   };
28);
29//This will subscribe to the TestRun system topic 
30listener = new RunTestListener(client, toolingConn);

Note

1import java.util.HashMap;
2import org.apache.commons.lang3.StringUtils;
3import org.cometd.bayeux.Message;
4import org.cometd.bayeux.client.ClientSessionChannel;
5import org.cometd.bayeux.client.ClientSessionChannel.MessageListener;
6import org.cometd.client.BayeuxClient;
7
8import com.sforce.soap.tooling.ApexTestQueueItem;
9import com.sforce.soap.tooling.ApexTestResult;
10import com.sforce.soap.tooling.QueryResult;
11import com.sforce.soap.tooling.SObject;
12import com.sforce.soap.tooling.SoapConnection;
13import com.sforce.soap.tooling.TestLevel;
14import com.sforce.ws.ConnectionException;
15
16public class RunTestListener {
17   private static final String CHANNEL = "/systemTopic/TestResult";
18   private SoapConnection conn;
19
20   public RunTestListener(BayeuxClient client, SoapConnection conn) {
21      this.conn = conn;  
22      System.out.println("Subscribing for channel: " + CHANNEL);  
23      client.getChannel(CHANNEL).subscribe(new MessageListener() {   
24         @Override
25         public void onMessage(ClientSessionChannel channel, Message message) {    
26            HashMap data = (HashMap) message.getData();    
27            HashMap sobject = (HashMap) data.get("sobject");    
28            String id = (String) sobject.get("Id");    
29            System.out.println("\nAysncApexJob " + id);    
30            getTestQueueItems(id);
31         }
32     }); 
33   }
34
35   public void runTests(String[] apexTestClassIds, String[] apexTestSuiteIds,
36      Integer maxFailedTests, String[] apexTestClassNames, String[] apexTestSuiteNames) {
37
38      // All parameters are required
39
40      if (apexTestClassIds == null && apexTestSuiteIds == null
41         && apexTestClassNames == null && apexTestSuiteNames == null) {
42         System.out.println("No tests to run");
43         return;
44      }
45      String classIds = StringUtils.join(apexTestClassIds,", ");
46      String suiteIds = StringUtils.join(apexTestSuiteIds,", ");
47      String classNames = StringUtils.join(apexTestClassNames,", ");
48      String suiteNames = StringUtils.join(apexTestSuiteNames,", ");
49
50      String tests = null;
51      Boolean skipCodeCover = false;
52
53      try {
54         System.out.println("Running async test run");
55         conn.runTestsAsynchronous(classIds, suiteIds, maxFailedTests,
56            TestLevel.RunSpecifiedTests, classNames, suiteNames, tests, skipCodeCover);
57      } catch (ConnectionException e) {
58         e.printStackTrace();
59      }
60   }
61   public void createAndRunTestsNode(String apexTestClassName,
62      String apexTestClassId, String[] apexTestMethods) {
63
64      //Currently, the array size of TestNode objects must be 1
65
66      //Provide a non-null class name or a non-null class ID
67      if (apexTestClassName != null && apexTestClassId != null) {
68         System.out.println("Specify a class name OR a class ID");
69         return;
70      } else if (apexTestClassName == null && apexTestClassId == null) {
71         System.out.println("No tests to run");
72         return;
73      }
74
75      TestsNode thisTestsNode = new TestsNode();
76      thisTestsNode.setClassName(apexTestClassName);
77      thisTestsNode.setClassId(apexTestClassId);
78      thisTestsNode.setTestMethods(apexTestMethods);
79      TestsNode[] tests = new TestsNode[] { thisTestsNode };
80
81      try {
82         System.out.println("Running async test run");
83         conn.runTestsAsynchronous(null, null, -1, null, null, null, tests);
84      } catch (ConnectionException e) {
85         e.printStackTrace();
86      }
87   }
88
89   private void getTestQueueItems(String asyncApexJobId) {
90      try {   
91         QueryResult res = conn     
92            .query("SELECT Id, Status, ApexClassId FROM ApexTestQueueItem
93               WHERE ParentJobId = '" + asyncApexJobId + "'");
94         if (res.getSize() > 0) {
95            for (SObject o : res.getRecords()) {     
96               ApexTestQueueItem atqi = (ApexTestQueueItem) o;     
97               System.out.println("\tApexTestQueueItem - "+atqi.getStatus());
98               if (atqi.getStatus().equals("Completed")) {      
99                  getApexTestResults(atqi.getId());     
100               }    
101            }   
102         } else {    
103            System.out.println("No queued items for " + asyncApexJobId);  
104         }  
105      } catch (ConnectionException e) {   
106         e.printStackTrace();  
107      } 
108   }
109
110   private void getApexTestResults(String apexTestQueueItemId) {
111      try {   
112         QueryResult res = conn     
113            .query("SELECT StackTrace,Message, AsyncApexJobId,MethodName, Outcome,ApexClassId
114               FROM ApexTestResult WHERE QueueItemId = '" + apexTestQueueItemId + "'");
115         if (res.getSize() > 0) {
116            for (SObject o : res.getRecords()) {     
117               ApexTestResult atr = (ApexTestResult) o;     
118               System.out.println("\tTest result for "       
119                  + atr.getApexClassId() + "." + atr.getMethodName());     
120               String msg = atr.getOutcome().equals("Fail") ? " - "       
121                  + atr.getMessage() + " " + atr.getStackTrace() : "";     
122               System.out.println("\t\tTest " + atr.getOutcome() + msg);    
123            }   
124         } else {    
125            System.out.println("No Test Results for " + apexTestQueueItemId);   
126         }  
127      } catch (ConnectionException e) {
128          e.printStackTrace();  
129      } 
130   }
131}

DID THIS ARTICLE SOLVE YOUR ISSUE?
Let us know so we can improve!