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
InsertWittyNameInsertWittyName 

Unit Testing Woes

Hi folks.

 

I have an Apex Trigger that I'm trying to write unit tests for.

 

The problem is I'm unsure how to test the following:

 

 

Opportunity newOpp = oldOpp.clone(false);

insert newOpp;

OpportunityLineItem oli = product.clone(false);

oli.OpportunityId = newOpp.Id;

oli.Objection__c = '';

oli.Outcome__c = '';

newProducts.add(oli);

 

 

Every line is marked as not tested and because of this my unit test fails.

 

Any advice?

 

Many thanks. 

Message Edited by InsertWittyName on 11-02-2009 07:46 AM
Message Edited by InsertWittyName on 11-02-2009 07:47 AM
jhenningjhenning

Is the code snippet part of the trigger or test method? Can you post the full trigger and the test method? I will be happy to look at them.

 

InsertWittyNameInsertWittyName

Hi John.

 

Many thanks for replying.

 

 

/* Any opps with Products that have an Outcome (Outcome__c) or Product Outcome (Objection__c) of 'Move to New Opp'. For each of these Products, Clone the existing opp (pre update) and add the Product. Reset the Outcome & Product Outcome. */ trigger tgrOppCreateNewOppsWithProducts on Opportunity (before update) { // Only fire on updates if (Trigger.isUpdate) { List <OpportunityLineItem> products = new List<OpportunityLineItem>(); List <OpportunityLineItem> newProducts = new List<OpportunityLineItem>(); List <Opportunity> opps = new List<Opportunity>(); List <Opportunity> newOpps = new List<Opportunity>(); List <Opportunity> oldOpps = new List<Opportunity>(); // Go through each updated record for (Integer i = 0; i < trigger.new.size(); i++) { Opportunity opp = trigger.new[i]; Opportunity oldOpp = trigger.old[i]; if(opp.HasOpportunityLineItem && opp.isClosed && !oldOpp.isClosed) { opps.add(opp); oldOpps.add(oldOpp); } } if(opps.size() > 0) { products = [Select Id, OpportunityId, PricebookEntryId, Quantity, Objection__c, Outcome__C from OpportunityLineItem where OpportunityId in :opps]; } for (Integer i = 0; i < opps.size(); i++) { Opportunity oldOpp = oldOpps[i]; for (OpportunityLineItem product : products) { // Check 'Product Outcome' and 'Outcome' if (product.Objection__c == 'Move to New Oppy' || product.Outcome__c == 'Move to New Opp') { // Clone pre-update opp. Opportunity newOpp = oldOpp.clone(false); newOpps.add(newOpp); // Clone Product, point to newOpp and reset outcomes OpportunityLineItem oli = product.clone(false); oli.Objection__c = ''; oli.Outcome__c = ''; newProducts.add(oli); } } } // Add the new Opps and Products if(newProducts.size() > 0) { insert newOpps; for(Integer i = 0; i < newProducts.size(); i++) { newProducts[i].OpportunityId = newOpps[i].Id; } insert newProducts; } } }

 

Test:

 

 

public class testTgrOppCreateNewOppsWithProducts { static testMethod void test() { //Create an Account Account account = new Account(name='Test Account 1'); insert account; //Create an Opportunity Opportunity opp = new Opportunity (name = 'Test Opp1', type = 'New Business', business_segment__c = 'AM100', stagename = 'New 0%', closedate = system.today(), ForecastCategoryName = 'Pipeline', accountid = account.id); insert opp; System.assert(opp != null); //Create a Product Product2 p = new Product2 (name = 'Some Product', Description = 'desc'); insert p; //Get standard pricebook Pricebook2 stdPb = [select Id from Pricebook2 where isStandard = true limit 1]; //Create pricebook entry PricebookEntry pbe = new PricebookEntry (pricebook2id = stdPb.id, product2id = p.id, unitprice = 1.0, isActive = true); insert pbe; //Insert opportunity line item OpportunityLineItem oli = new OpportunityLineItem (OpportunityId = opp.Id, PricebookEntryId = pbe.Id, Quantity = 1, UnitPrice = 1); insert oli; OpportunityLineItem oli2 = new OpportunityLineItem (OpportunityId = opp.Id, PricebookEntryId = pbe.Id, Quantity = 2, UnitPrice = 2); insert oli2; // Update oli, setting Outcome__c/Objection__c to Move to New Opp (fire the trigger) oli.Objection__c = 'Move to New Opp'; oli.Outcome__c = 'Move to New Opp'; update oli; System.assert(oli != null); System.assertEquals(oli.Objection__c, 'Move to New Opp'); System.assertEquals(oli.Outcome__c, 'Move to New Opp'); // Now change to closed won opp.StageName = 'Closed Won'; opp.Reason_Closed_Won__c = 'Price'; update opp; System.assert(opp != null); } }

 

 

 

 Many thanks.

 

Message Edited by InsertWittyName on 11-02-2009 06:01 PM
Bvanb-zNetBvanb-zNet

What is have found is that when creating a trigger, put all the code in a subordanate apex class makes things a lot easier and simplifies with code reuse.

 

Thus

 /* trigger */

 

trigger tgrOppCreateNewOppsWithProducts on Opportunity (after insert, before update) { tr_OppCreateNewOppsWithProducts opCreate = new tr_OppCreateNewOppsWithProducts (Trigger.New,trigger.IsUpdate,trigger.IsInsert); opCreate.DoTrigger(); return; } // end trigger public class tr_OppCreateNewOppsWithProducts { public class My1Exception extends Exception {} boolean IsUpdate = false; boolean IsInsert = false; boolean IsAfter = false; list <Opportunity> CVs ; public tr_OppCreateNewOppsWithProducts () {} public tr_OppCreateNewOppsWithProducts (list<Opportunity xCVs, boolean xisUpdate,boolean xisInsert) { CVs = xCVs; this.IsUpdate=xIsUpdate; this.IsInsert=xisInsert; } public boolean DoTrigger() { etc.... } }

 

 

Thus all your code is in a standard class which you can then build test cases for without having to force a trigger being fired. 

 

Bruce

Message Edited by Bvanb-zNet on 11-03-2009 09:32 AM
jhenningjhenning

I tried your code and was able to achieve 100% code coverage with a couple of minor changes:

1. You don't need the if(Trigger.isUpdate), since the trigger is only using the "after Update" action.

2. When I tried running your code, the trigger was throwing an exeception, the "TotalPrice" is a required field on products, I see that you are cloning the OpportunityLineItems but your "select" statement did not include TotalPrice. I changed line 24 to include TotalPrice:

 

 

products = [Select Id, OpportunityId, PricebookEntryId, Quantity, TotalPrice, Objection__c, Outcome__C from OpportunityLineItem where OpportunityId in :opps];

 

3. You should use a deep clone for lines 37 and 41 of your code:

 

 

Opportunity newOpp = oldOpp.clone(false, true); OpportunityLineItem oli = product.clone(false, true);

 

 With these changes the test method ran with 100% coverage.