9

I am using AgentWork trigger in my logic and I cannot achieve code coverage goal.

Simple test method:

Id cId = [SELECT Id From Case Where Subject = 'Case Subject'].Id;
User u = [SELECT Id From User LIMIT 1];
ServiceChannel sc = [SELECT Id FROM ServiceChannel WHERE DeveloperName = 'Service_Channel_Test' LIMIT 1];

System.runAs(u)
{
    List<AgentWork> agentWorks = new List<AgentWork>();
    agentWorks.add(new AgentWork(WorkItemId = cId, UserId = u.Id, ServiceChannelId = sc.Id));

insert agentWorks;

}

returns

System.DmlException: Insert failed. First exception on row 0; first error: FIELD_INTEGRITY_EXCEPTION, The agent's status is not associated with the channel for this work.: [ServiceChannelId]

Because of manipulation of UserServicePresence is not permitted then I cannot move forward. I suppose that, currently it is not supported by SFDC. Which is funny because test coverage is obligatory.

Do you have any experience with AgentWork unit tests?

5
  • This is a very interesting question that hasn't been discussed much online. Has anybody found a solution?
    – feddus
    Feb 19, 2016 at 9:10
  • Does it helps : developer.salesforce.com/forums/?id=906F00000005KVYIA2 ------- See comments Feb 22, 2016 at 15:24
  • 1
    @SalesforceSteps I tried everything on the link. It doesn' help. Aug 28, 2019 at 6:22
  • @SaumyaGaikwad I always wanted to answer this, but it skipped my mind. Thanks for bounty which made me remeber writing solution. Our org had recent OmniChannel implementation and this is how I managed to solve. Aug 28, 2019 at 13:31
  • Solution is simple. Don't have a Trigger on AgentWork. Use Process Builder to execute the code you need to run.
    – dBeltowski
    Aug 30, 2019 at 15:17

5 Answers 5

3

This is a very interesting scenario, which everyone faced while testing/deploying omnichannel. Inserting is not allowed and as manish porwal suggested you have to make test running user as active on OmniChannel to get coverage for AgentWorkTrigger. This makes unit testing hard and impossible for CI/CD as someone has to manually go and make test running user as active to test class to pass.

So the requirement boils down to:

1) How to achieve some coverage on AgentWork Trigger?

2) How to unitest them without inserting then?

The logic lies in beforeInsert trigger, consider the order of execution:

The key point to note here is, in insert the before insert trigger runs first and then the system validation steps.

The exception you mentioned:

: Insert failed. First exception on row 0; first error: FIELD_INTEGRITY_EXCEPTION, The agent's status is not associated with the channel for this work.: [ServiceChannelId]

happens after the before insert trigger, thus if you catch that, you can have some coverage in trigger thus it can be deployed without making any user as active in OmniChannel.

Things get simpler if you write a single line trigger and make your handler do everything:

trigger AgentWorkTrigger on AgentWork (before insert, after update) {

    AgentWorkTriggerHandler.run();

}

public class AgentWorkTriggerHandler{

    public static void run(){

        switch on Trigger.operationType {
            when BEFORE_INSERT {
                System.debug('Before Insert'); //For Test
            }
            when AFTER_UPDATE {
                agentWorkService.doMyLogic(Trigger.new);//Your Service method
            }
        }

    }

}

Now to test trigger for coverage

@isTest
private static testTriggerCoverage(){

ServiceChannel sc = [SELECT Id
                FROM ServiceChannel WHERE DeveloperName = 'TestUnit'
                LIMIT 1];
Case caseRec = [SELECT Id FROM Case LIMIT 1];
User systemUser = [SELECT Id FROM User WHERE FirstName = 'System'];


System.runAs(systemUser){
    //Try Catch is to ensure test doesn't fail in cisit and ciuat
    try{
        AgentWork aw = new AgentWork(
                ServiceChannelId = sc.Id,
                WorkItemId = caseRec.Id,
                UserId = systemUser.Id
        );
        insert aw;

        aw.MyField__c = 'Submitted';
        update aw;
    }catch(Exception ex){
        //Exception will occur due to the omni channel bug. Ignore it

}

}

Here, I am catching the exception to have some coverage for AgentTrigger

Now you code logic now exists in Handlers/Service methods, thus you can mock Trigger.new, old, newMap,Oldmap and send it to your service methods and get them covered.

Resources: https://developer.salesforce.com/forums/?id=906F00000005KVYIA2

4
  • Annotate your run method with @InvocableMethod and call it from Process Builder. Then you won't need the AgentWork trigger at all.
    – dBeltowski
    Aug 30, 2019 at 15:20
  • You saved the day; thanks! Jun 24, 2020 at 19:06
  • @WillemMulder happy to help. This gave me many sleepless nights .:) Jun 25, 2020 at 19:42
  • Yes, because if this didn't work, the Trigger would not deploy at all. Ever. Because it needs > 0% coverage :-( So thanks again!! :-D Jun 26, 2020 at 8:21
0

I have faced the similar situation in my test class related to AgenWorkTrigger. To have a successful run for the test class, the logged in user should be available on the omnichannel and after that test class should be run.

0

My solution was to simply NOT HAVE AN AGENT WORK TRIGGER!

Put all your logic in a separate class. Now annotate the entry method with @InvocableMethod and call that method from the Process Builder.

BAM! No more AgentWork trigger, no more requirements for test coverage, no more errors about FIELD_INTEGRITY ServiceChannelId bunk, no more logging into Omni-Channel during deployments.

You can test your InvocableMethod without actually inserting or updating AgentWork.

Example Helper Class

public class AgentworkTriggerHelper
{
    @InvocableMethod
    public static void agentworkStatusUpdate(List<AgentWork> newAgentWorkList)
    {
        ... your logic here ...
    }
}

Example Test Class

public class AgentworkTriggerHelperTest
{
    @isTest static void agentWork()
    {
        AgentWork aw = new AgentWork();
        aw.serviceChannelId = schannel.Id;

        List<AgentWork> aworksList = new List<AgentWork>{aw};

        AgentworkTriggerHelper.agentworkStatusUpdate(aworksList);
    }
{
0

I have an iffy workaround for getting >1% coverage if you are are not using this trigger and are just trying to get through deployment (it will possibly work even if you are using the trigger but that's not what we used it for).

The problem as I understand it is that there is no way to insert a agent work trigger as one of the required fields cannot be filled. This means that the insert will fail, however by adding 'before insert' to our trigger we can cause it to run regardless and we can get some limited coverage with our test:

Replace agent work trigger with:

trigger AgentWorkTrigger on AgentWork(after insert, after update, before insert) {

    if (Trigger.isAfter) {
        wkdw.AgentWorkTriggerHandlerGlobalProxy.handleTrigger(
            Trigger.newMap,
            Trigger.oldMap,
            Trigger.operationType
        );

    } else if (Trigger.isBefore) {
        //Here to support test coverage
    }
}

And add the following test:

@isTest

public class AgentWorkTriggerTest {

    @IsTest
    public static void Test_triggerAgentWork(){
        AgentWork aw = new AgentWork();
        Boolean recordInserted = false;

        Test.startTest();
        Database.SaveResult sr = Database.Insert(aw,false);
        Test.stopTest();

        if (sr.isSuccess()) {
            //Not expecting success from this insert as mandatory fields are missing, e.g. ServiceChannel
            recordInserted = True;
        }

        System.assertEquals(false, recordInserted);
    }
}

This test literally checks for the insert failing and runs no real code from the trigger. Ideally, salesforce would spend less time marketing buzzwords and more time fixing bugs and improving the developer side so we don't have to do things like this. This bug delayed a production deployment by more than a day 😤

-1

Try this ugly code, worked in my case.

aw is an AgentWork instance

    for (ServiceChannel sc : [select Id from ServiceChannel limit 10]){
        try {
            w.ServiceChannelId = sc.Id;
            insert w;
            break;
        }catch(Exception e) {
            System.debug(LoggingLevel.INFO, 'Service channel with id '+sc.Id+' is invalid');
        }
    }

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .