+ Start a Discussion
wcwill978wcwill978 

Need Help Increasing Test Coverage

Hi I have a trigger that creates a custom object when an opportunity stage is set to "closed lost" and saved. I created a test class to deploy into prod, but can only get 64%coverage. Can someone help me increase my test coverage or guide me in the right dirrection so I can get as close to 100% Also when I run the test I get one Test Failure: System.DmlException: Insert failed. First exception on row 0; first error: REQUIRED_FIELD_MISSING, Required fields are missing: [CloseDate]: [CloseDate]

 

Below is my test Class:

 

@isTest
private class MyTestWLATrigger
{
    static testmethod void TestMethod1()
    {
        //Fill all mandatory properties of opportunity and don't miss stage name
        Opportunity opp = new Opportunity() ;
        opp.Name = 'Test Oppty' ;
        opp.stageName = '4: Generate Offer' ;
        opp.WonLostReason1__c = '' ;
        //Now insert the opportunity
        insert opp ;
        
        //To let your trigger code covered in write this
        opp.stageName = 'Closed Lost' ;
        //change the stage name
        opp.WonLostReason1__c = 'Price' ;
        //Now update the opportunity
        update opp ;
        System.assertEquals(opp.Name, opp.stageName, opp.WonLostReason1__c);
        
    }
}

And below is my trigger:

 

trigger AutoCreateWinLossAnalysisOnOpportunity on Opportunity (after update) 
{

  List<Opportunity> closedOps = new List<Opportunity>();
  List<Win_Loss_Analysis__c> newwinLossObjects = new List<Win_Loss_Analysis__c>();  
  List<Win_Loss_Analysis__c> updatewinLossObjects = new List<Win_Loss_Analysis__c>();
  
  List<RecordType> recordTypesForOppty = new List<RecordType>();
  recordTypesForOppty = [Select Name, ID From RecordType where SobjectType = 'Win_Loss_Analysis__c'];
  System.debug('recordTypesForOppty'+recordTypesForOppty);
  
    List<Id> ExistingIds = new List<Id>();
    
     
    Integer  count = Trigger.new.size(); 
    for(Opportunity newvalue : Trigger.new)
    {
      Opportunity oldvalue = Trigger.oldMap.get(newvalue.Id);
        if(oldvalue.StageName != newvalue.StageName || oldvalue.WonLostReason1__c != newvalue.WonLostReason1__c)  
       {
           if(newvalue.StageName == 'Closed Lost'){
            if(newvalue.WonLostReason1__c == 'Price' 
              || newvalue.WonLostReason1__c == 'Product Feature/Functionality' 
              || newvalue.WonLostReason1__c =='Relationship')
            {
            System.debug('newvalue'+newvalue);
               closedOps.add(newvalue);
                 ExistingIds.add(newvalue.Id);
       
            }
          }
       }
    }
    system.debug('Found : ' + closedOps.size() + ' Opps that need analysis records created');
    if (closedOps.size() > 0)  
    { 
      List<Win_Loss_Analysis__c> existing = [SELECT Id,Opportunity_Name__c FROM Win_Loss_Analysis__c WHERE  Opportunity_Name__c  in :ExistingIds];
      system.debug('Found : ' + existing.size() + ' Existing Win Loss Records');
      string LossAnalysis = null;
      for (Opportunity oppty : closedOps)
      {       
              // get the recordTypeId
              Id WinLossObjectRecordTypeId = null;
              string typeName;
              LossAnalysis = oppty.WonLostReason1__c.toLowerCase();
              System.debug('******LossAnalysis *******'+LossAnalysis);
          for (RecordType recordType : recordTypesForOppty)
          {
          
          System.debug('recordType'+recordType);
            typeName = recordType.Name.toLowerCase();
            
            System.debug('recordType.Name.toLowerCase()>>>>>>>'+recordType.Name.toLowerCase());
              System.debug('******typeName *******'+typeName );
            if (LossAnalysis == 'price' && typeName == 'price (lost)') 
            {
            
            System.debug('ist if>>>>>>');
              WinLossObjectRecordTypeId = recordType.Id;
            }
            if (LossAnalysis == 'product feature/functionality' && typeName == 'productfeature (lost)') 
            {
             System.debug('2nd if>>>>>>');
              WinLossObjectRecordTypeId = recordType.Id;
            }
            if (LossAnalysis == 'relationship' && typeName == 'relationship (lost)') 
            {
             System.debug('3rd if>>>>>>');
              WinLossObjectRecordTypeId = recordType.Id;
            }
          }
          system.debug('Record type id: ' + WinLossObjectRecordTypeId + ' found for oppt id' + WinLossObjectRecordTypeId );
              // construct the new custom object with the required fields set
              
              Win_Loss_Analysis__c wL = new Win_Loss_Analysis__c();
              System.debug('oppty.Id>>>>>>>'+oppty.Id);
              wL.Opportunity_Name__c = oppty.Id;
              wL.RecordTypeId = WinLossObjectRecordTypeId;
              System.debug('*************Checking RecordTypeId***********'+WinLossObjectRecordTypeId);
              System.debug('WinLossObjectRecordTypeId>>>>>>>'+WinLossObjectRecordTypeId);
              wL.Account_Name__c = oppty.AccountId;
               System.debug('oppty.AccountId>>>>>>>'+oppty.AccountId);
              if(existing.size() > 0)
              {
                   for(Win_Loss_Analysis__c exist : existing)
                {
                  if(exist.Opportunity_Name__c == oppty.Id)
                  {
                    wL.Id = exist.Id;
                    break;  
                  }              
                }
              }
              
              if(wL.Id == null)
              {
                newwinLossObjects.add(wL);
              }
              else
              {
                updatewinLossObjects.add(wL);
              }
              
      }
    }
    system.debug('Inserting ' + newwinLossObjects.size() + ' new Win Loss Objects' );
    system.debug('Updating ' + updatewinLossObjects.size() + '  Win Loss Objects' );
    if(newwinLossObjects.size() > 0)
         insert newwinLossObjects;
   
    if(updatewinLossObjects.size() > 0)
         update updatewinLossObjects;

}
Best Answer chosen by Admin (Salesforce Developers) 
sfdcfoxsfdcfox

Assertion Failed means that your trigger or Apex Classes executed all the way through, but there was a logic error (according to your test method). Consider this obvious example:

 

 

public class MyClass {
  public integer myInt { get; set; }
  // This function has a logic error.
  public void addOne() { myInt = myInt + 2; }
  public MyClass() { myInt=0; }

  public static testMethod void testAddOne() {
    MyClass cc = new MyClass();
    cc.addOne();
    system.assertEquals(1, cc.myInt);
  }
}

 In this code, I'm expecting myInt to be the value 1, but because of a typo, myInt will actually be 2. This will cause the System.Exception as you posted (except something like "Expected: 1, Actual: 2"). Doublecheck your logic to make sure that the test actually models what you're trying to do, and then doublecheck your functions to make sure they're actually written the way they're supposed to be. This check and balance system is exactly why code coverage is forced upon us hapless developers. It makes us consider our code carefully to ensure that we're getting the results we expect.

 

All Answers

DCBoyDCBoy

In your test method, add opp.closedate = date.today(); after the 8th line.

wcwill978wcwill978

Thank you DCBoy,

 

I added this line, and it decreased my overall test coverage down to 44%. On my trigger though it covered it at 84%.

 

Average test coverage across all Apex Classes and Triggers is 44% and now received this new error:

 

System.DmlException: Update failed. First exception on row 0 with id 006T0000007ZCMYIA4; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, AutoCreateWinLossAnalysisOnOpportunity: execution of AfterUpdate caused by: System.DmlException: Insert failed. First exception on row 0; first error: REQUIRED_FIELD_MISSING, Required fields are missing: [Account_Name__c]: [Account_Name__c] Trigger.AutoCreateWinLossAnalysisOnOpportunity: line 109, column 10: []

 

 

DCBoyDCBoy

To make sure you are setting all the required fields in your test method, create a new opportunity from the UI and note down all the fields that are mandatory. All of those need to be set in your test method as well.

wcwill978wcwill978

Hi DCBoy,

 

All the required fields for when the oppty is closed are already set in the test method. That error message for the required field [Account_Name__c] is a custom field in the custom object that the trigger is creating. This Account name is automatically pulled from the oppty and auto filled by the trigger. Here is the updated trigger: When I run this now the overall test coverage decreased.

 

 

@isTest
private class MyTestWLATrigger
{
    static testmethod void TestMethod1()
    
    {
        Account a = new Account(Name='Test Acct');
        insert a;
        
        //Fill all mandatory properties of opportunity and don't miss stage name
        Opportunity opp = new Opportunity() ;
        opp.closedate = date.today();
        opp.Name = 'Test Oppty' ;
        opp.stageName = '4: Generate Offer' ;
        opp.WonLostReason1__c = '' ;
        //Now insert the opportunity
        insert opp ;
        
        //To let your trigger code covered in write this
        a.Name = 'Test Acct' ;
        opp.Name = 'Test Oppty' ;
        opp.closedate = date.today();
        opp.stageName = 'Closed Lost' ;
        //change the stage name
        opp.WonLostReason1__c = 'Price' ;
        //Now update the opportunity
        update opp ;
        
        System.assertEquals('Closed Lost', 'Price');
        
    }
}
DCBoyDCBoy

You need to associated the account created in the first line (Account a) to the opportunity record being inserted (opp.accountid = a.id;)

wcwill978wcwill978

That got rid of the errors, but my code coverage is still at 21% I dont get it. Before it was at 64% and now its this low. Also this new message poped up:

 

System.Exception: Assertion Failed: Expected: Closed Lost, Actual: Price

sfdcfoxsfdcfox

Assertion Failed means that your trigger or Apex Classes executed all the way through, but there was a logic error (according to your test method). Consider this obvious example:

 

 

public class MyClass {
  public integer myInt { get; set; }
  // This function has a logic error.
  public void addOne() { myInt = myInt + 2; }
  public MyClass() { myInt=0; }

  public static testMethod void testAddOne() {
    MyClass cc = new MyClass();
    cc.addOne();
    system.assertEquals(1, cc.myInt);
  }
}

 In this code, I'm expecting myInt to be the value 1, but because of a typo, myInt will actually be 2. This will cause the System.Exception as you posted (except something like "Expected: 1, Actual: 2"). Doublecheck your logic to make sure that the test actually models what you're trying to do, and then doublecheck your functions to make sure they're actually written the way they're supposed to be. This check and balance system is exactly why code coverage is forced upon us hapless developers. It makes us consider our code carefully to ensure that we're getting the results we expect.

 

This was selected as the best answer