function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion

Strange trigger test error on Lead conversion

Sorry if this post seems confusing


I'm seeing a strange error that I think has to do with the timing of events in salesforce's unit tests.

Essentially all I've built is a trigger that makes the original creator of a Lead auto-follow the chatter feed for the Account and Opportunity after the Lead is converted.

See the following trigger on the opportunity that performs this:

	trigger ChatterAutoFollowOpportunity on Opportunity (after insert) {

    List<ID> opportunityIds = new List<ID>();
    for (Opportunity opp : {
    	System.debug('opp.Id: ' + opp.Id);
    List<EntitySubscription> followAccounts = new List<EntitySubscription>();
    List<EntitySubscription> followOpps = new List<EntitySubscription>();
    for(Lead lead : [SELECT ID, ConvertedOpportunityId, ConvertedAccountId, CreatedById FROM Lead where ConvertedOpportunityId IN :opportunityIds ]){
        EntitySubscription followAccount = new EntitySubscription (
                                 parentId = lead.ConvertedAccountId,
                                 subscriberid = lead.CreatedById);
        EntitySubscription followOpp = new EntitySubscription (
                                parentId = lead.ConvertedOpportunityId,
                                subscriberid = lead.CreatedById);

    insert followAccounts;
    insert followOpps;


This trigger works great for us, and I've tested it manually.  The problem comes in when I wrote my unit test for this trigger:

private class ProspectConvertTest {
    static testMethod void myUnitTest() {
    //User user = [select id from User where alias = 'itest'];
        Lead newLead = new Lead(Company='My Test Lead', LastName = 'UnitTest');
        //newLead.CreatedById = user.Id;
        insert newLead;
        Database.LeadConvert lc = new database.LeadConvert();
LeadStatus convertStatus = [SELECT Id, MasterLabel FROM LeadStatus WHERE IsConverted=true LIMIT 1];
Database.LeadConvertResult lcr = Database.convertLead(lc);
//Lead has been converted.  Check the lead, account, and opportunity
Lead existingLead = [Select id, isConverted, ConvertedAccountId, ConvertedOpportunityId, createdbyid FROM Lead where id =];
List<EntitySubscription> esList = [Select parentId, SubscriberId from EntitySubscription where parentid in (:existingLead.ConvertedAccountId, :existingLead.ConvertedOpportunityId) and SubscriberId = :existingLead.createdbyid];
System.assert(existingLead.ConvertedAccountId != null);
System.assert(existingLead.ConvertedOpportunityId != null);
//this is the statement that fails
System.assertEquals(2, esList.size());


The last line in that unit test does not assert properly.  When run in a unit test, the EntitySubscriptions that are created in the trigger dont exist.  When I look at the code coverage, it is missing all the lines inside the for loop...which essentially tells me that the ConvertedOpportunityId is not being populated in the trigger.  The odd thing is that the trigger works fine when I convert a Lead using the UI.  Even odder is that If I run this query in the Trigger, it succeeds:

Lead convertedLead = [SELECT ID, ConvertedOpportunityId, ConvertedAccountId, CreatedById FROM Lead where ConvertedOpportunityId = :existingLead.ConvertedOpportunityId ];
System.assert(convertedLead != null);


So my problem is, why is the convertedOpportunityId populated in the unit test after the trigger is executed, but not before, and also why does it work when not run in a unit test?
Sorry if this is confusing....I can clarify with any questions.

Just s stab at it...


is any of this happening asyncronously by SF design or in a @future call?


Try adding the test.startTest() and test.stopTest() methods to your code to ensure all asyncronous calls are completed for the test.




Hmmm....sounds like a great idea.  My thoughts over lunch was some sort of race condition on a seperate thread for lead conversion.  I'll give it a shot.


No luck....


One of things though about the tests is that salesforce doesn't commit any of the data and does a rollback.  So once the test completes ,you can't see any of the data that your test used.  Normally this is a good thing, but I'm wondering if the reason the convertLead method requires a commit for the convertedaccountid to be filled in.






If so, it has to do with what you are specifically trying to do and since we do not currently convert leads I am not familiar with the process. I do know that I use system.assertEquals all the time in my test methods and they work fine as the data is not rolled back until the test method is over. They do not roll back at test.StopTest()...


Sorry I could not be of more help...


I was under the impression that unless you went out of your way to disable it, the owners of converted leads were already automatically subscribed to the feeds from the newly created objects:


Automatic feed subscriptions: When you convert a lead into an account, contact, and (optionally) an opportunity, the owner of the generated records is automatically subscribed and the lead owner is unsubscribed from the lead record. Any users that were subscribed to the lead are now subscribed to the generated records and unsubscribed from the lead. This means that the lead owner and other users that were subscribed to the lead see any changes to the account, contact, and opportunity records in their news feed. The subscription occurs unless the user has selected the Stop automatically following records checkbox in Your Name | Setup | My Chatter Settings | My Feeds A user can subscribe to a record so that changes to the record are displayed in the news feed on the user's home page. This is a useful way to stay up-to-date with changes to records in Salesforce.



So, as long as you make sure that Lead owners are subscribed to their Leads before conversion, you should be all set.






Having said that, with your current approach, I think you may have a transactional consistency problem.   You:


1. Create a Lead

2. Convert the Lead which:

2A: Creates an Account

2B: Creates a Contact

2C: Creates an Opportunity

2D: Creates OpportunityContactRole

3: NOW the Lead Conversion is complete.   


Until step 3 I don't think the Lead Conversion is completed.  So, in step 2C (your Opportunity Trigger), even though the opportunity has been created, I don't believe the results of the lead conversion have been placed back into the Lead until step 3.   For example, what if some problem with the creation of the Opportunity Contact Role created an exception, the whole Lead Creation would, I think, be rolled back.


So, I may be totally wrong, and truthfully, I'm not sure.   But I don't believe your approach will work.





So, perhaps a cleaner way to do this would be as an After Update trigger on the Lead object that first checks to see if the Lead in the trigger has just been converted:


for (Lead l: {

    if (l.isConverted && !trigger.oldmap.get( {




Best, Steve.


p.s. It's 4:22am... my brain my be a bit foggy.  Caveat Emptor.