0

i wrote a function that whenever an account owner is changed, if there is an opportunity with a specific type, avoid changing it's owner. because it's not really possible, what i did is save the old owner of the opportunity, and after the update is done and the owner is changed, revert it back to the old owner.

That's the code, and it works perfectly fine (partial, not the entire class):

public class AccountTriggerHandler extends TriggerHandler {
    protected override void beforeUpdate(){
        avoidOpportunityOwnerChangeOnOwnerChangeBeforeUpdate();
    }

    protected override void afterUpdate(){          
        if(!beforeUpdateMap.isEmpty())
        {
            avoidOpportunityOwnerChangeOnOwnerChangeAfterUpdate(testSetId,beforeUpdateMap);
        }
    }

    static map<id,id> beforeUpdateMap;

    public void avoidOpportunityOwnerChangeOnOwnerChangeBeforeUpdate()
    {
        System.debug('avoidOpportunityOwnerChangeOnOwnerChangeBeforeUpdate');
        if(AccountTriggerHandler.isExecutingavoidOpportunityOwnerChangeOnOwnerChangeBeforeUpdate && !Test.isRunningTest() ){ 
            return;
        }
        AccountTriggerHandler.isExecutingavoidOpportunityOwnerChangeOnOwnerChangeBeforeUpdate = true;

        List <Account> newAccountList = (List<Account>)Trigger.New;

        Map <Id, Account> oldAccountMap = (Map <Id, Account>)Trigger.oldMap;    

        Set<Id> newAccSetId = new Set<Id>();

        for( Account acc_i: newAccountList)
        {
            if(acc_i.OwnerId != oldAccountMap.get(acc_i.Id).OwnerId)
            {
                newAccSetId.add(acc_i.id);
            }
        }

        list<Opportunity> opps = [Select id, accountid, isClosed, Type, ownerid, owner.name from Opportunity where accountid in :newAccSetId];
        beforeUpdateMap=new map<id,id>();

        for(Opportunity opp_i : opps){
            System.debug('opp_i: ' + opp_i);    
            if(!opp_i.isClosed && opp_i.type == 'Renewal Business')
            {
                beforeUpdateMap.put(opp_i.Id,opp_i.ownerid);
            }
        }
        System.debug('beforeUpdateMap after func avoidOpportunityOwnerChangeOnOwnerChangeBeforeUpdate: ' + beforeUpdateMap);
    }

    public static boolean isExecutingavoidOpportunityOwnerChangeOnOwnerChangeAfterUpdate = false;

    @future
    public static void avoidOpportunityOwnerChangeOnOwnerChangeAfterUpdate(Set<Id> newAccSetId,map<id,id> beforeUpdateMap) 
    {
        System.debug('avoidOpportunityOwnerChangeOnOwnerChangeAfterUpdate');
        if(AccountTriggerHandler.isExecutingavoidOpportunityOwnerChangeOnOwnerChangeAfterUpdate){ 
            return;
        }

        AccountTriggerHandler.isExecutingavoidOpportunityOwnerChangeOnOwnerChangeAfterUpdate = true;

        list<Opportunity> updateOpps = new list<Opportunity>();

        Set<Id> oppSetId = new Set<Id>();
        oppSetId = beforeUpdateMap.keySet();

        list<Opportunity> opps = [Select id, type, isClosed, accountid, ownerid, owner.name from Opportunity where id in:oppSetId];

        for(Opportunity opp_i : opps){
            id a = beforeUpdateMap.get(opp_i.Id);
            opp_i.OwnerId = a;
            updateOpps.add(opp_i);
        }
        system.debug('opps to revert owner after account owner change: ' + updateOpps);
        if(!updateOpps.isEmpty())
        {
           update updateOpps;
        }
    }
}

now, i wanted to write a test class for it. notice there is a future method called "avoidOpportunityOwnerChangeOnOwnerChangeAfterUpdate". it should retrieve the old owner.

that's the test i wrote: (UPDATED AFTER YOUR SUGGESTIONS)

@isTest private static void testavoidOpportunityOwnerChangeOnOwnerChange()
    {
        Account accountTest = TestUtil.getAccountByName('AccountTestAvoid');
        insert accountTest; 

        Opportunity testOpp = TestUtil.getOpportunityByNameAndStage('TestOne', 'Customer Confirmed Quote', accountTest.id);
        testOpp.type = 'Renewal Business';
        insert testOpp;

        Account acc = [SELECT Id, Name,OwnerID from Account Where name = 'AccountTestAvoid' limit 1];
        Opportunity opp = [SELECT id,name,ownerId from opportunity limit 1];

        Profile p = [SELECT Id FROM Profile where name ='system administrator' limit 1]; 
        User usr = TestUtil.getUserByNameAndProfileId('test',p.Id);
        insert usr ;

        accountTest.ownerId = usr.id;

        Test.startTest();
         update accountTest;
        Test.stopTest();

        Account accRes = [SELECT Id, Name,OwnerID from Account Where name = 'AccountTestAvoid' limit 1];
        Opportunity oppRes = [SELECT id,name,ownerId from opportunity limit 1];

        System.debug('accRes.OwnerId: ' + accRes.OwnerId);
        System.debug('acc.OwnerId: ' + acc.OwnerId);
        System.debug('oppRes.OwnerId: ' + oppRes.OwnerId);
        System.debug('opp.OwnerId: ' + opp.OwnerId);
        System.AssertNotEquals(accRes.OwnerId,acc.OwnerId);
        System.AssertNotEquals(oppRes.OwnerId,opp.OwnerId);
    }

The second assert fails, and seems like the opportunity owner is not changed at all. in the UI - When the account records transferred to another user, the associated open opportunities automatically transferred to the new account owner without firing the opportunity trigger.

(Whenever an account owner is changed, all the opportunities owners are changed to the same one, didnt happen here)

how can i simulate the same process in a test class?

3 Answers 3

2

When we write test class for Asynchronous Apex then we have to wrap that action in Test.startTest() and Test.stopTest() which kicks off the execution of Asynchronous Apex.

In your case when you are updating the Owner of Account Record then you calling that method. So you should update the Account between startTest and stopTest.

Test.startTest();
update accountTest;
Test.stopTest();

And then check the asserts with OwnerId.

System.AssertNotEquals(accRes.OwnerId,acc.OwnerId);
System.AssertNotEquals(oppRes.OwnerId,opp.OwnerId);
1
  • i did what you wrote, but im having another issue. i updated the question
    – Dana Griff
    Commented Jan 30, 2018 at 11:19
1

To test a future method, you need to call Test.stopTest().

    accountTest.ownerId = usr.id;
    Test.startTest();
    update accountTest;

    Test.stopTest();
    Account accRes = [SELECT Id, Name,OwnerID from Account Where name = 'AccountTestAvoid' limit 1];
    Opportunity oppRes = [SELECT id,name,ownerId from opportunity limit 1];

When you call Test.stopTest, it causes future methods, queueable methods, scheduled methods, or batchable methods to execute synchronously. You can then query the data back (as you've done here) to verify the behavior of the method called.

1
  • i did what you wrote, but im having another issue. i updated the question
    – Dana Griff
    Commented Jan 30, 2018 at 11:19
0

did you ever get this working? I an deperately in need on the same solution (for Contacts, rather than Oppty's). If you could please get back to me I would greatly appreaciate it. Thanks in advance.

Sean

1
  • 1
    Please don't post questions as an answer next time, but as a comment. i did exactly like the accepted solution.
    – Dana Griff
    Commented Jan 15, 2020 at 10:59

You must log in to answer this question.

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