[SalesForce] Documentation Incorrect? Is it possible to cover/deploy triggers on Platform Events

I am about to roll out some code which uses Platform Events, and hitting a troublesome roadblock in testing. Is calling Test.stopTest() supposed to cause subscriber triggers to fire and subsequently process published events?

No matter what I try, I cannot seem to get the subscriber triggers to fire in a test context. That leads to 0% coverage on the trigger body, which in turn means the trigger cannot be deployed.


The documentation states:

Usage
Each test method is allowed to call this method only once. Any code that executes after the stopTest method is assigned the original limits that were in effect before startTest was called. All asynchronous calls made after the startTest method are collected by the system. When stopTest is executed, all asynchronous processes are run synchronously.

The pub/sub logic seems asynchronous. Conclusion: trigger should fire!


The Platform Event Developer Guide also touches on testing (emphasis mine):

Ensure that your platform event trigger is working properly by adding an Apex test. Before you can package or deploy any Apex code
(including triggers) to production, your Apex code must have tests. To publish platform events in an Apex test, enclose the publish
statements within Test.startTest() and Test.stopTest() statements.

Call the publish method within the Test.startTest() and Test.stopTest() statements. In test context, the publish
method enqueues the publish operation. The Test.stopTest() statement causes the event publishing to be carried out. Include
your validations after the Test.stopTest() statement.

// Create test events
Test.startTest();
// Publish test events
Test.stopTest();
// Perform validation here

Conclusion: trigger should fire!


However, the behavior I observe is that the subscriber trigger never fires, even after calling Test.stopTest(). Here is the basic structure I am trying to test:

Trigger

trigger MyEvent on MyEvent__e (after insert)
{
    MySubscriber.doStuff(trigger.new); // not covered
}

Subscriber

public with sharing class MySubscriber
{
    public static void doStuff(List<MyEvent__e> events)
    {
        // implementation
        // not covered
    }
}

Test

static testmethod void testMySubscriberTrigger()
{
    List<MyEvent__e> events = new List<MyEvent__e>
    {
        new MyEvent__e(/*data*/)
    };

    Test.startTest();
        EventBus.publish(events);
    Test.stopTest();

    // make assertions
}

However, I get 0% coverage on my subscriber trigger, and none of the subscriber implementation gets covered either. Is the documentation wrong in this regard? How can I cover the trigger itself?

Every class and trigger involved is set to API Version 40.0.


I tried using plain old insert instead of publishing:

// instead of:
// EventBus.publish(events);
// I tried:
insert events;

But I got this error:

System.DmlException: Argument must be of internal SObject type.


I also tried throwing an exception in the trigger to prove if it runs or not:

trigger MyEvent on MyEvent__e (after insert)
{
    throw new DmlException('This trigger is running');
}

However, the test passed without any exception encountered.


I have so far tested this functionality on CS14 and raised a case on this issue today (#16685012).

Best Answer

Sounds like a bug.

We are looking into this now. Testing was working last week, and it is working in our development environments.

More to come...

Jay Hurst (Director, Product Management for Enterprise API and Enterprise Messaging at Salesforce)


Thanks to everyone for your patience. We identified the issue and are pushing a fix on Tuesday evening/Wednesday. Tests should work after.

https://twitter.com/extraidea/status/875874669433245696


Based on Adrian's comment, this appears to be fixed in Summer '17 Patch 10.0.

Related Topic