1

I'm trying to get code coverage for my trigger for when I deploy my trigger to production. This is my first time trying to provide code coverage to a Trigger in SalesForce, as I'm new to creating these kind of classes. I have the following trigger:

trigger UpdateOpportunity on Opportunity (after insert, before update){    

   Map<Id, Opportunity> recordTypeMap = new Map<Id, Opportunity>([SELECT RecordType.Name FROM Opportunity WHERE ID IN :Trigger.new]);  

   for(Opportunity opp : Trigger.new){

      if(recordTypeMap.get(opp.Id).RecordType.Name == 'SGI Opportunity' && opp.StageName != 'Lead 0%'){

             if(opp.Win_Reason__c == 'No Competition/Sole Source'){

                opp.Competitor_s__c = 'No Competitor/Sole Source'; 

            }

               if(opp.Unsolicited_Bid__c == 'Yes'){

                  opp.Competitor_s__c = 'No Competitor/Sole Source';

            } 

         }
    }
}

For my test class, I have the following:

@isTest
private class UpdateOpportunityTest {

    static testMethod void UpdateOpportunityTest() {

        Id sgiOpportunityRecordTypeId = [SELECT Id FROM RecordType WHERE Name = 'SGI Opportunity'].Id;

        Opportunity opportunity = new Opportunity(
          Name = 'Test Opportunity', Opportunity_Type__c = 'Add-On',
            Product_Revenue_Type__c = '% of Completion', CloseDate = Date.today(), StageName = 'Lead 0%',
            CurrencyIsoCode = 'USD', Opportunity_Intergaph_Line_of_Business__c = 'Government', Solution__c = 'Border Security',
            OwnerId = UserInfo.getUserId(), RecordTypeId = sgiOpportunityRecordTypeId);
        insert opportunity;

        Test.startTest();
        try {
          insert opportunity;
        }
        catch (DmlException ex) {

      System.assertEquals(StatusCode.FIELD_CUSTOM_VALIDATION_EXCEPTION, ex.getDmlType(0));
      System.assertEquals('Cannot delete a Contact with associated Opportunities.', ex.getDmlMessage(0));
        }
        Test.stopTest();
    }
}

And I get the following error when I try and run the test:

Error Message   System.AssertException: Assertion Failed: Expected: FIELD_CUSTOM_VALIDATION_EXCEPTION, Actual: INVALID_FIELD_FOR_INSERT_UPDATE

Stack Trace Class.UpdateOpportunityTest.UpdateOpportunityTest: line 21, column 1

I'm lost at to what I'm doing wrong with this TEST class.

Any help is greatly appreciated! Thanks for your time in advance!

1
  • try a "system.debug('Status Code: ' + ex.getMessage() );" before the assert. See what is actually there.
    – Jagular
    Commented Sep 26, 2014 at 15:40

2 Answers 2

3

First off, this is very good for a first test code attempt, you clearly did some research and have a pretty good understanding, so great job.

I think your assertion statement is actually fine, the issue is that you are trying to insert the opportunity twice. If you remove the first insert statement (outside of the try block), this should work.

@isTest
private class UpdateOpportunityTest {

    static testMethod void UpdateOpportunityTest() {

        Id sgiOpportunityRecordTypeId = [SELECT Id FROM RecordType WHERE Name = 'SGI Opportunity'].Id;

        Opportunity opportunity = new Opportunity(
          Name = 'Test Opportunity', Opportunity_Type__c = 'Add-On',
            Product_Revenue_Type__c = '% of Completion', CloseDate = Date.today(), StageName = 'Lead 0%',
            CurrencyIsoCode = 'USD', Opportunity_Intergaph_Line_of_Business__c = 'Government', Solution__c = 'Border Security',
            OwnerId = UserInfo.getUserId(), RecordTypeId = sgiOpportunityRecordTypeId);

        insert opportunity;   // DELETE THIS LINE

        Test.startTest();
        try {
          insert opportunity; 
        }
        catch (DmlException ex) {

      System.assertEquals(StatusCode.FIELD_CUSTOM_VALIDATION_EXCEPTION, ex.getDmlType(0));
      System.assertEquals('Cannot delete a Contact with associated Opportunities.', ex.getDmlMessage(0));
        }
        Test.stopTest();
    }
}

EDIT

Also, a great catch by @AlexTennant. In addition to the double DML statement, there is an issue int he trigger itself. You are trying to do a direct field update on values in the trigger context variables. This is fine for before triggers, but not after triggers. Your trigger should be before insert and before update, not after update.

Change this

trigger UpdateOpportunity on Opportunity (after insert, before update){

to this

trigger UpdateOpportunity on Opportunity (before insert, before update){    

You can take a look at the documentation around trigger context variables and considerations here.

https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_triggers_context_variables_considerations.htm

5
  • Alex, great catch, I saw the double Insert statement and assumed that was the ONLY issue. You are correct, and I missed that. Thanks Commented Sep 26, 2014 at 15:40
  • Thank you so much for the kind words and for the resolution as my TEST class has now passed! :) I looked at my trigger and it's now saying the code coverage is at 42%. Code coverage is suppose to be at 75%, so how do I get it up to that standard? Thanks again! Commented Sep 26, 2014 at 15:48
  • You just need to make sure you are checking all branches of your logic. It looks like in your trigger you are checking for certain values of Win_Reason__c and Unsolicited_Bid__c. When you create opportunities to test in your test class, you need to make sure you check all combinations for these values and assert the outcome is as you expect it to be. Commented Sep 26, 2014 at 16:01
  • There is a problem with the current try catch implementation, if insert opportunity; succeeds inside try then it wouldn't hit catch so it will always pass. Ensuring EnsureCatchClause.setTry(); inside try and EnsureCatchClause.setCatch(); inside the catch and then system.assert(EnsureCatchClause.isErrorCaught(), EnsureCatchClause.assertMessage()); outside the try catch will ensure it is taking the rigt path. I have added the suggested edit onto this answer. Commented Feb 11, 2021 at 0:38
  • It is much easier to write ‘system,assert(false);’ after the insert than add an entirely new class and methods. Commented Feb 11, 2021 at 1:39
1

You are trying to insert the Opportunity twice. You cannot specify Id in an insert call.

There are a couple of other things you should consider changing though. First of all, if your try block succeeds, you will not assert anything at all in your test. So at the very least, you should assert false at the end of your try block. I find that a better pattern is more like so:

DmlException expectedException;
Test.startTest();
    try
    {
        //Do stuff to throw exception
    }
    catch (DmlException dmx)
    {
        expectedException = dmx;
    }
Test.stopTest();

system.assertNotEquals(null, dmx, 'An error should be thrown.');
system.assertEquals(EXPECTED_STATUS_CODE, dmx.getStatusCode(), 'Informative message');

This way, if your try block succeeds, you still get an assertion failure. Try to keep your assertions in sections of the code that will always run, as opposed to try/catch or if/else blocks.

Second of all, always move your logic outside your trigger body. A handler pattern is a pretty good way to go. Logic in the trigger body runs without sharing and will make it very difficult to maintain One Trigger Per Object as your logic gets more complex.

You must log in to answer this question.

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