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
Alex MerwinAlex Merwin 

Help creating an APEX Test Class for Opportunity Triggers

Hey guys - 

I'm struggling to develop a Test Case for three triggers I need to promote on the Opportunity object. 

New to APEX and appreciate any help!

Here is where I've gotten for the Test Case: 
@isTest 
public class TestOLITriggers {
    static testMethod void insertNewOpportunity() {
       
       Opportunity opportunityToCreate = new Opportunity();
       
       // Do you recognize these fields?
       opportunityToCreate.StageName = 'Sourcing Demand';
       opportunityToCreate.CloseDate = '2016-01-01';
       opportunityToCreate.Account = '0015000000tVJRS';
       opportunityToCreate.Name = 'Test Opportunity Triggers';

       // Don't worry about these
       opportunityToCreate.TimeZoneSidKey    = 'America/Denver';
       opportunityToCreate.LocaleSidKey      = 'en_US';
       opportunityToCreate.EmailEncodingKey  = 'UTF-8';
       opportunityToCreate.LanguageLocaleKey = 'en_US';
       
       insert opportunityToCreate;
    }
}

And the three Opportunity Triggers. 
 
trigger OLIUpdate on Opportunity (after update) {
    Set<Id> oppIds = new Set<Id>();

    RecordType rt = [
        select Id
        from RecordType
        where Name = 'Strategic Audience Plan'
    ];

    for (Opportunity opp : Trigger.new) {
        Opportunity oldOpp = Trigger.oldMap.get(opp.Id);
        if (
            opp.StageName == 'Notify Demand' &&
            oldOpp.StageName != opp.StageName &&
            opp.RecordTypeId == rt.Id
        ) {
            oppIds.add(opp.Id);
        }
    }

    if (!oppIds.isEmpty()) {
        List<OpportunityLineItem> oliList = [
            select Campaign_Status__c,
                INTL_Demand_Approval__c
            from OpportunityLineItem
            where OpportunityId in :oppIds
        ];

        for (OpportunityLineItem oli : oliList) {
            if (oli.INTL_Demand_Approval__c != 'Local Demand must approve buyer before Launch Ticket can be deployed') {
                oli.Campaign_Status__c = 'Buyer Approved, Ready to Launch';
            } else {
                oli.Campaign_Status__c = 'Buyer Approved, Pending Local Demand Approval';
            }
        }

        update oliList;
    }
}

trigger OLIUpdate_SAP_SendLaunchTickets on Opportunity (after update) {
    Set<Id> oppIds = new Set<Id>();

    for (Opportunity opp : Trigger.new) {
        Opportunity oldOpp = Trigger.oldMap.get(opp.Id);
        if (
            opp.StageName == 'Deploy Launch Tickets' &&
            oldOpp.StageName != opp.StageName 
        ) {
            oppIds.add(opp.Id);
        }
    }

    if (!oppIds.isEmpty()) {
        List<OpportunityLineItem> oliList = [
            select Campaign_Status__c
            from OpportunityLineItem
            where OpportunityId in :oppIds
        ];

        for (OpportunityLineItem oli : oliList) {
            oli.Campaign_Status__c = 'Buyer Approved, Ready to Launch';
        }

        update oliList;
    }
}


 
trigger OLIUpdate_SAP_BuyerApproval on Opportunity (after update) {
    Set<Id> oppIds = new Set<Id>();

    for (Opportunity opp : Trigger.new) {
        Opportunity oldOpp = Trigger.oldMap.get(opp.Id);
        if (
            opp.StageName == 'Responded to Buyer' &&
            oldOpp.StageName != opp.StageName
        ) {
            oppIds.add(opp.Id);
        }
    }

    if (!oppIds.isEmpty()) {
        List<OpportunityLineItem> oliList = [
            select Campaign_Status__c
            from OpportunityLineItem
            where OpportunityId in :oppIds
        ];

        for (OpportunityLineItem oli : oliList) {
            oli.Campaign_Status__c = 'Buyer Approval Needed';
        }

        update oliList;
    }
}


 
pconpcon
Since all three of your triggers are update triggers you will need to update the opportunity in order for them to fire.  For you last trigger for example, you will want to update StageName to Responded to Buyer.  You will also need to create a OpportunityLineItem beforehand.
 
@isTest
public class TestOLITriggers {
    static testMethod void insertNewOpportunity() {
        Opportunity testOpportunity = new Opportunity(
            StageName = 'Sourcing Demand',
            CloseDate = '2016-01-01',
            Account = '0015000000tVJRS',
            Name = 'Test Opportunity Triggers',
            TimeZoneSidKey = 'America/Denver',
            LocaleSidKey = 'en_US',
            EmailEncodingKey  = 'UTF-8',
            LanguageLocaleKey = 'en_US'
        );
        insert testOpportunity;

        OpportunityLineItem testOLI = new OpportunityLineItem(
            OpportunityId = testOpportunity.Id,
            // Any other data you need
        );
        insert testOLI;

        testOpportunity.StageName = 'Responded to Buyer';

        Test.startTest();

        update testOpportunity;

        Test.stopTest();

        OpportunityLineItem result = [
            select Campaign_Status__c
            from OpportunityLineItem
            where Id = testOLI.Id
        ];

        System.assertEquals(
            'Buyer Approval Needed',
            result.Campaign_Status__c,
            'The status was not updated properly'
        );
    }
}
NOTE: This code has not been tested and may contain typographical or logical errors

I would recommend that you have a test class per trigger and that you also read over this document [1] to look at the additional tests you should be writing.  Take this test above as a template.  If you have any specific problems with your tests please let us know.

[1] http://blog.deadlypenguin.com/blog/testing/strategies/
Alex MerwinAlex Merwin
Thanks for this, I appreciate the help on this and other threads. Starting to see how this works..

I think there may be a typo in the template code, I'm getting this error: 

Compile Error: unexpected token: ')' at line 19 column 8
pconpcon
If you do not add additional data on line 18 then you will need to remove the comma at the end of line 17
Alex MerwinAlex Merwin
Got pulled away from this for a few weeks, still having some trouble. This is making sense now and it's clear to me how to modify the APEX Class for each individual trigger to test. The referenced article was very helpful as well. 

We have a lot of required fields on our page layouts that aren't really critical for testing the functionality of the Triggers, so I created a new Opportunity Record Type called 'APEX Test' with a corresponding page layout which has the bare minimum fields for testing the desired behavior. 

There are two lookup fields on the Test Class that reference IDs that will be different in our Production Org, do I need to take this into account when writing the APEX Test Class? 
  1. RecordTypeID
    1. Sandbox ID: 0124B0000008fEj
    2. Production ID: 01238000000UUj8
  2. DSP__c >> this is a Lookup field to a related Account. There is a validation rule on the OLI that restrict the Triggers from firing if this field isn't populated. I've created a Dummy account in our Sandbox and Production orgs for this to point to so the validation rule doesn't limit the records from being updated. 
    Sandbox ID: 0014B000004lew6
    Production ID: 00138000018DiwD
I'm getting the following compile errors. When I remove one offending field I get the subsequent errors. I've saved the test Class with all these fields removed but of course the test fails because it's missing required fields for the Opportunity object.

Can you help? 
  1. Error: Compile Error: Invalid field TimeZoneSidKey for SObject Opportunity
  2. Error: Compile Error: Invalid field LocaleSidKey for SObject Opportunity
  3. Error: Compile Error: Invalid field EmailEncodingKey for SObject Opportunity
  4. Error: Compile Error: Invalid field LanguageLocaleKey for SObject Opportunity
  5. Error: Compile Error: Invalid initial expression type for field Opportunity.CloseDate, expecting: Date
@isTest
public class TestOLITriggers_SAP_BuyerApproval {
    static testMethod void insertNewOpportunity() {
        Opportunity testOpportunity = new Opportunity(
            RecordTypeID = '0124B0000008fEj',
            Name = 'Test Opportunity Triggers',
            CloseDate = '2016-01-01',            
            StageName = 'Sourcing Demand',
            DSP__c = '0014B000004lew6',
            TimeZoneSidKey = 'America/Denver',
            LocaleSidKey = 'en_US',
            EmailEncodingKey  = 'UTF-8',
            LanguageLocaleKey = 'en_US'
        );
        insert testOpportunity;

        OpportunityLineItem testOLI = new OpportunityLineItem(
            OpportunityId = testOpportunity.Id
            // Any other data you need
        );
        insert testOLI;

        testOpportunity.StageName = 'Responded to Buyer';

        Test.startTest();

        update testOpportunity;

        Test.stopTest();

        OpportunityLineItem result = [
            select Campaign_Status__c
            from OpportunityLineItem
            where Id =: testOLI.Id
        ];

        System.assertEquals(
            'Buyer Approval Needed',
            result.Campaign_Status__c,
            'The status was not updated properly'
        );
    }
}

 
Alex MerwinAlex Merwin
Sorry, I forgot to review required fields at the OLI level. The below code includes a reference to a Dummy Product to be used by the APEX test class. Similar question on this lookup field as what applied to RecordTypeID and DSP__c above. 

Product2
  • Sandbox Product ID: 01t4B000000W42J
  • Product Product ID: 01t38000003LZid

Thanks!
 
@isTest
public class TestOLITriggers_SAP_BuyerApproval {
    static testMethod void insertNewOpportunity() {
        Opportunity testOpportunity = new Opportunity(
            RecordTypeID = '0124B0000008fEj',
            Name = 'Test Opportunity Triggers',
            CloseDate = '2016-01-01',            
            StageName = 'Sourcing Demand',
            DSP__c = '0014B000004lew6',
            TimeZoneSidKey = 'America/Denver',
            LocaleSidKey = 'en_US',
            EmailEncodingKey  = 'UTF-8',
            LanguageLocaleKey = 'en_US'
        );
        insert testOpportunity;

        OpportunityLineItem testOLI = new OpportunityLineItem(
            OpportunityId = testOpportunity.Id ,
            Product2 = '01t4B000000W42J'
            // Any other data you need
        );
        insert testOLI;

        testOpportunity.StageName = 'Responded to Buyer';

        Test.startTest();

        update testOpportunity;

        Test.stopTest();

        OpportunityLineItem result = [
            select Campaign_Status__c
            from OpportunityLineItem
            where Id =: testOLI.Id
        ];

        System.assertEquals(
            'Buyer Approval Needed',
            result.Campaign_Status__c,
            'The status was not updated properly'
        );
    }
}

 
Alex MerwinAlex Merwin
I just figued out how to solve one of my 'association' issues between IDs being different between production and sandbox. I updated the Validation Rule to exclude my APEX Test Opportunity Record Type, below code reflects this is no longer part of the test. I can't figure out how to remove the reference to the Record Type ID itself though (to give me the 'simple' layout and required fields) and the Product2 (to get Price information on the OLI)...

And of course the Compile Errors. 
 
@isTest
public class TestOLITriggers_SAP_BuyerApproval {
    static testMethod void insertNewOpportunity() {
        Opportunity testOpportunity = new Opportunity(
            RecordTypeID = '0124B0000008fEj',
            Name = 'Test Opportunity Triggers',
            CloseDate = '2016-01-01',            
            StageName = 'Sourcing Demand',
            TimeZoneSidKey = 'America/Denver',
            LocaleSidKey = 'en_US',
            EmailEncodingKey  = 'UTF-8',
            LanguageLocaleKey = 'en_US'
        );
        insert testOpportunity;

        OpportunityLineItem testOLI = new OpportunityLineItem(
            OpportunityId = testOpportunity.Id ,
            Product2 = '01t4B000000W42J'
            // Any other data you need
        );
        insert testOLI;

        testOpportunity.StageName = 'Responded to Buyer';

        Test.startTest();

        update testOpportunity;

        Test.stopTest();

        OpportunityLineItem result = [
            select Campaign_Status__c
            from OpportunityLineItem
            where Id =: testOLI.Id
        ];

        System.assertEquals(
            'Buyer Approval Needed',
            result.Campaign_Status__c,
            'The status was not updated properly'
        );
    }
}


 
pconpcon
You shoul NEVER hardcode Ids in your tests, and you should ALWAYS create all of the objects you need to use.  So for example, your test above should be modified to:
 
@isTest
public class TestOLITriggers_SAP_BuyerApproval {
    static testMethod void insertNewOpportunity() {
        RecordType rt = [
            select Name
            from RecordType
            where Name = 'My Record Type'
        ];

        Product2 testProduct = new Product2(
            Name = 'Happy Funtime Ball'
        );
        insert testProduct;

        Opportunity testOpportunity = new Opportunity(
            RecordTypeID = rt.Id,
            Name = 'Test Opportunity Triggers',
            CloseDate = '2016-01-01',         
            StageName = 'Sourcing Demand',
            TimeZoneSidKey = 'America/Denver',
            LocaleSidKey = 'en_US',
            EmailEncodingKey  = 'UTF-8',
            LanguageLocaleKey = 'en_US'
        );
        insert testOpportunity;

        OpportunityLineItem testOLI = new OpportunityLineItem(
            OpportunityId = testOpportunity.Id,
            Product2 = testProduct.Id
            // Any other data you need
        );
        insert testOLI;

        testOpportunity.StageName = 'Responded to Buyer';

        Test.startTest();

        update testOpportunity;

        Test.stopTest();

        OpportunityLineItem result = [
            select Campaign_Status__c
            from OpportunityLineItem
            where Id = :testOLI.Id
        ];

        System.assertEquals(
            'Buyer Approval Needed',
            result.Campaign_Status__c,
            'The status was not updated properly'
        );
    }
}

The "layout" based on the record type does not come into play at all when writing tests.  The only fields that will be required in testing are the ones that are marked as required at the object level, not at the layout level.
Alex MerwinAlex Merwin
Thanks, that makes sense. 

Any ideas on the Compile Errors from these fields? They are still popping up with the updated code: 
  • Error: Compile Error: Invalid field TimeZoneSidKey for SObject Opportunity
  • Error: Compile Error: Invalid field LocaleSidKey for SObject Opportunity
  • Error: Compile Error: Invalid field EmailEncodingKey for SObject Opportunity
  • Error: Compile Error: Invalid field LanguageLocaleKey for SObject Opportunity
  • Error: Compile Error: Invalid initial expression type for field Opportunity.CloseDate, expecting: Date
Also, there is a new Compile Error now on the Product2 object: 
  • Error: Compile Error: Field is not writeable: Product2 at line 24 column 24
When I delete all fields causing Compile Errors I can save the class but it is failing tests with the following Test Report: 
User-added image

Here's the code that generated the above test, I know it isn't right given the missing fields just need advise on how to deal with the compile errors before I can move forward: 
 
@isTest
public class TestOLITriggers_SAP_BuyerApproval {
    static testMethod void insertNewOpportunity() {
        RecordType rt = [
            select Name
            from RecordType
            where Name = 'My Record Type'
        ];

        Product2 testProduct = new Product2(
            Name = 'Happy Funtime Ball'
        );
        insert testProduct;

        Opportunity testOpportunity = new Opportunity(
            RecordTypeID = rt.Id,
            Name = 'Test Opportunity Triggers',     
            StageName = 'Sourcing Demand'
        );
        insert testOpportunity;

        OpportunityLineItem testOLI = new OpportunityLineItem(
            OpportunityId = testOpportunity.Id
            // Any other data you need
        );
        insert testOLI;

        testOpportunity.StageName = 'Responded to Buyer';

        Test.startTest();

        update testOpportunity;

        Test.stopTest();

        OpportunityLineItem result = [
            select Campaign_Status__c
            from OpportunityLineItem
            where Id = :testOLI.Id
        ];

        System.assertEquals(
            'Buyer Approval Needed',
            result.Campaign_Status__c,
            'The status was not updated properly'
        );
    }
}




 
pconpcon
Well you're getting that exception since you did not update line 07 to set the name of your record typ.
pconpcon
As for the other fields, none of them exist on the Opportunity object (except for CloseDate) so I don't know why you are trying to set them.

As for ClosedDate, use the following:
 
ClosedDate = Date.parse('01/01/2016')

 
Alex MerwinAlex Merwin
Hmm... I made the update for our Opportunity Record Type name but am still getting all the same Compile errors just noted. 

Thanks for your help with this. 
 
@isTest
public class TestOLITriggers_SAP_BuyerApproval {
    static testMethod void insertNewOpportunity() {
        RecordType rt = [
            select Name
            from RecordType
            where Name = 'Strategic Audience Plan'
        ];

        Product2 testProduct = new Product2(
            Name = 'Happy Funtime Ball'
        );
        insert testProduct;

        Opportunity testOpportunity = new Opportunity(
            RecordTypeID = rt.Id,
            Name = 'Test Opportunity Triggers',
            CloseDate = '2016-01-01',         
            StageName = 'Sourcing Demand',
            TimeZoneSidKey = 'America/Denver',
            LocaleSidKey = 'en_US',
            EmailEncodingKey  = 'UTF-8',
            LanguageLocaleKey = 'en_US'
        );
        insert testOpportunity;

        OpportunityLineItem testOLI = new OpportunityLineItem(
            OpportunityId = testOpportunity.Id,
            Product2 = testProduct.Id
            // Any other data you need
        );
        insert testOLI;

        testOpportunity.StageName = 'Responded to Buyer';

        Test.startTest();

        update testOpportunity;

        Test.stopTest();

        OpportunityLineItem result = [
            select Campaign_Status__c
            from OpportunityLineItem
            where Id = :testOLI.Id
        ];

        System.assertEquals(
            'Buyer Approval Needed',
            result.Campaign_Status__c,
            'The status was not updated properly'
        );
    }
}

 
pconpcon
Again, the TimeZoneSidKey, LocaleSidKey, EmailEncodingKey and LanguageLocaleKey are not valid fields for the Opportunity.  You will need to remove them.  As for CloseDate you will need to use
 
CloseDate = Date.parse('01/01/2016')