0

I am pretty new to Apex triggers and Apex Class Tests but i have written and deployed a couple successfully so far. But i am having real problems with a new trigger that i have created.

I have created a trigger that will create Assets (in a custom object (Don't ask!)) when an opportunity is closed Won. The trigger works in sandbox and has 100% Code Coverage with the Test in sandbox.

But when i try and deploy to production i get the following error:

Code Coverage Failure The following triggers have 0% code coverage. Each trigger must have at least 1% code coverage. CreateAssetonClosedWon

Do you have any idea what would cause this to happen?

Trigger below:

trigger CreateAssetonClosedWon on Opportunity (after insert, after update) {
     for(Opportunity o: trigger.new){ 
      if(o.isWon == true && o.HasOpportunityLineItem == true){
         String opptyId = o.Id;
         OpportunityLineItem[] OLI = [Select UnitPrice, Quantity, PricebookEntry.Product2Id, PricebookEntry.Product2.Name, Description, Converted_to_Asset__c, Module__c, Product_Family__c
                                      From OpportunityLineItem 
                                      where OpportunityId = :opptyId  and Converted_to_Asset__c = false and Product_Family__c <> 'Support and Maintenance' and Product_Family__c <> 'Professional Services' and Product_Family__c <> 'Discount'];
         Asset_Custom__c[] ast = new Asset_Custom__c[]{};
         Asset_Custom__c a = new Asset_Custom__c();
         for(OpportunityLineItem ol: OLI){
            a = new Asset_Custom__c();
            a.Account__c = o.AccountId;
            a.Product__c = ol.PricebookEntry.Product2Id;
            a.Sale_Price__c =  ol.UnitPrice;
            a.Quantity__c = ol.Quantity;
            a.Purchase_Date__c = o.CloseDate;
            a.Install_date__c = o.CloseDate;
            a.Active_Cancelled__c = 'Active';
           // a.Description = ol.Description;
           // a.Name = ol.PricebookEntry.Product2.Name;
           // a.Module__c = ol.Module__c;
            ast.add(a);
            ol.Converted_to_Asset__c = true;
       }
      update OLI; 
      insert ast;
     }
    }
}

Test:

@isTest(seealldata=true)


private class testCreateAssetonClosedWon {

  static testMethod void testCreateAssetonClosedWon(){

    Account a = [select Id from Account limit 1];
    PricebookEntry pbID = [select Id from PricebookEntry WHERE IsActive = TRUE limit 1];
    Opportunity o = new Opportunity();
    OpportunityLineItem ol = new OpportunityLineItem ();
    Contact c = [select Id from Contact Limit 1];
    Id nodemo = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get('No Demo').getRecordTypeId();


    o.RecordTypeId = nodemo;
    o.AccountId = a.Id;
    o.Primary_Contact__c = c.id;
    o.Name = 'test';
    o.StageName = 'Opportunity Started';
    o.CloseDate = date.today();
    o.type = 'Quote';
    o.LeadSource= 'Cold Call';
    insert o;

    ol.OpportunityId = o.Id;
    ol.Quantity = 1;
    ol.UnitPrice = 2.00;
    ol.PricebookEntryId = pbId.Id;

    insert ol;

    o.StageName= 'Closed Won';
    update o;

    delete ol;
    delete o;



  }


}

Any help with this would be really appreciated.

8
  • 4
    You shouldn't use the (seealldata=true) annotation. The problem might be that your production org doesn't include any account, contact or pricebookEntry. You shoud insert your test data inside your test. Sep 5, 2017 at 9:00
  • If i remove (seealldata=true) the test fails in the sandbox.
    – Benjy Hunt
    Sep 5, 2017 at 9:03
  • Of course it does. This is because your test is badly written as I said before. Sep 5, 2017 at 9:04
  • Ok, So please can you give me some guidance on what needs to be changed, Please can you provide a bit more information on what you mean by "You shoud insert your test data inside your test."?
    – Benjy Hunt
    Sep 5, 2017 at 9:08
  • Just insert a new account, a new contact, a new pricebookentry before inserting your opportunity. Sep 5, 2017 at 9:10

1 Answer 1

2

Few things in your code that you must keep in practice:

  • Avoid (seealldata = true) in test class
  • Avoid Queries and DML's inside Loops
  • Try using Maps
  • Avoid initializing variables inside loop

I believe creating an OpportunityLineItem in Test class is a bit of headache. How to Create Opportunity Line Items in Test Classes --> Follow This Link for creating line item in test class. This helps me always.

   trigger CreateAssetonClosedWon on Opportunity (after insert, after update) {
    Map<Id, Opportunity> OpportyMap = new Map<Id, Opportunity>();
    List<Asset_Custom__c> ast = new List<Asset_Custom__c>();
    Asset_Custom__c a = new Asset_Custom__c();
    for(Opportunity o: trigger.new){ 
        if(o.isWon == true && o.HasOpportunityLineItem == true){
            OpportyMap.put(o.Id,o);
        }
    }

    List<OpportunityLineItem> OLI = new List<OpportunityLineItem>([Select UnitPrice, Quantity, PricebookEntry.Product2Id, PricebookEntry.Product2.Name, Description, Converted_to_Asset__c, Product_Family__c, OpportunityId From OpportunityLineItem  where  Converted_to_Asset__c = false and Product_Family__c != 'Support and Maintenance' and Product_Family__c  != 'Professional Services' and Product_Family__c != 'Discount' and OpportunityId In :OpportyMap.Keyset()]);

    for(OpportunityLineItem ol: OLI){
        a.Account__c = OpportyMap.get(ol.OpportunityId).AccountId;
        a.Product__c = ol.PricebookEntry.Product2Id;
        a.Sale_Price__c =  ol.UnitPrice;
        a.Quantity__c = ol.Quantity;
        a.Purchase_Date__c = OpportyMap.get(ol.OpportunityId).CloseDate;
        a.Install_date__c = OpportyMap.get(ol.OpportunityId).CloseDate;
        a.Active_Cancelled__c = 'Active';
        // a.Description = ol.Description;
        // a.Name = ol.PricebookEntry.Product2.Name;
        // a.Module__c = ol.Module__c;
        ast.add(a);
        ol.Converted_to_Asset__c = true;
    }

    update OLI; 
    insert ast;

}

And the test Class

 @isTest
private class testCreateAssetonClosedWon {

    static testMethod void testCreateAssetonClosedWon(){

        Account a =new Account(Name = 'New Test Account');
        Opportunity o = new Opportunity();    
        Contact c = new Contact(LastName = 'New Contact');
        Id nodemo = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get('No Demo').getRecordTypeId();
        o.RecordTypeId = nodemo;
        o.AccountId = a.Id;
        o.Primary_Contact__c = c.id;
        o.Name = 'test';
        o.StageName = 'Opportunity Started';
        o.CloseDate = date.today();
        o.type = 'Quote';
        o.LeadSource= 'Cold Call';
        insert o;

        Product2 prod = new Product2(
            Name = 'Product X',
            ProductCode = 'Pro-X',
            isActive = true
        );
        insert prod;
        Id pricebookId = Test.getStandardPricebookId();
        //Create your pricebook entry
        PricebookEntry pbEntry = new PricebookEntry(
            Pricebook2Id = pricebookId,
            Product2Id = prod.Id,
            UnitPrice = 100.00,
            IsActive = true
        );
        insert pbEntry;

        //create your opportunity line item.  This assumes you already have an opportunity created, called opp
        OpportunityLineItem oli = new OpportunityLineItem(
            OpportunityId = o.Id,
            Quantity = 5,
            PricebookEntryId = pbEntry.Id,
            TotalPrice = 5 * pbEntry.UnitPrice
        );
        insert oli;


        o.StageName= 'Closed Won';
        update o;

    }


}
8
  • 1
    It is a better practice to create a test data factory class and call that from all test methods, but creating in the test class is much better than using seeAllData.
    – Dave Humm
    Sep 5, 2017 at 10:48
  • 1
    Yes @DaveHumm, This is just one solution to the code. I prefer TestDataFactory in case i have plenty of Triggers. But this can be used as a unified approach Sep 5, 2017 at 10:51
  • Why the suggestion to use list<> instead of []
    – Eric
    Sep 5, 2017 at 12:24
  • @Eric lists are elastic and can grow as needed provided that you use the List add method to add new elements follow the link -> salesforce.stackexchange.com/questions/5447/… Sep 5, 2017 at 12:27
  • You do know that [] is a list in apex right? List<account> is the same as account[]
    – Eric
    Sep 5, 2017 at 12:29

You must log in to answer this question.

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