You need to sign in to do that
Don't have an account?
Alaric Wimer
Why is my test class assertion failing?
I have a trigger that updates the quantity of one opportunity product when another one's quantity is updated. Everything seems to be working when I mess around in the sandbox. However, the last test class assertion keeps failing. Does anyone know why it's failing? Any help is greatly appreciated.
Here's my trigger:
trigger UpdateInverterQuantity on OpportunityLineItem (before update) { Map<Id, Product2> prodMap = new Map<Id, Product2>([ SELECT Id, Name FROM Product2 WHERE Name = 'Heliene 60M-BLK 310W' OR Name = 'Heliene 60M-HBLK 300W' ]); for (OpportunityLineItem oli : Trigger.new) { // Get related inverter from same opportunity List<OpportunityLineItem> inverters = [ SELECT Id, Quantity, Product2.Name FROM OpportunityLineItem WHERE OpportunityId = :oli.OpportunityId AND (Product2.Name = 'APSystems QS1' OR Product2.Name = 'YC600') LIMIT 1 ]; if (prodMap.ContainsKey(oli.Product2Id)) { // panel 1 or panel 2 // Get quantity of panels if (!inverters.isEmpty()) { // set inverter quantity formulas Decimal inverterQuantityOne = (inverters.get(0).Quantity / 4); Decimal inverterQuantityTwo = (inverters.get(0).Quantity / 2); inverterQuantityOne = inverterQuantityOne.round(System.RoundingMode.CEILING); inverterQuantityTwo = inverterQuantityTwo.round(System.RoundingMode.CEILING); // update quantity of inverter if (inverters.get(0).Product2.Name == 'APSystems QS1') { // inverter 1 inverters.get(0).Quantity = inverterQuantityOne; } else if (inverters.get(0).Product2.Name == 'YC600') { // inverter 2 inverters.get(0).Quantity = inverterQuantityTwo; } update inverters; } } } }
And here's my test class:
@isTest private class UpdateInverterQuantityTest { @isTest static void updatePanelQuantity() { // create an opportunity Opportunity myOpp = new Opportunity(); myOpp.Name = 'Test'; myOpp.StageName = 'Closed Won'; myOpp.CloseDate = Date.today(); myOpp.Pricebook2Id = Test.getStandardPricebookId(); insert myOpp; Id pricebookId = Test.getStandardPricebookId(); //Create your panel Product2 panel = new Product2( Name = 'Heliene 60M-HBLK 300W', ProductCode = 'H300W', isActive = true ); insert panel; //Create your inverter Product2 firstInverter = new Product2( Name = 'APSystems QS1', ProductCode = 'APS', isActive = true ); insert firstInverter; //Create your pricebook entry for panel PricebookEntry panelEntry = new PricebookEntry( Pricebook2Id = pricebookId, Product2Id = panel.Id, UnitPrice = 100.00, IsActive = true ); insert panelEntry; //Create your pricebook entry for inverter PricebookEntry inverterEntry = new PricebookEntry( Pricebook2Id = pricebookId, Product2Id = firstInverter.Id, UnitPrice = 100.00, IsActive = true ); insert inverterEntry; // add panel to opp products OpportunityLineItem oli = new OpportunityLineItem( OpportunityId = myOpp.Id, Quantity = 20, PricebookEntryId = panelEntry.Id, TotalPrice = 20 * panelEntry.UnitPrice ); insert oli; // add inverter to opp products OpportunityLineItem oli2 = new OpportunityLineItem( OpportunityId = myOpp.Id, Quantity = 20, PricebookEntryId = inverterEntry.Id, TotalPrice = 20 * inverterEntry.UnitPrice ); insert oli2; // Get updated inverter quantity OpportunityLineItem inverter = [ SELECT Quantity FROM OpportunityLineItem WHERE OpportunityId = :oli.OpportunityId AND Id = :oli2.Id LIMIT 1 ]; System.assertEquals(5, inverter.Quantity); // Update quantity of panels oli.Quantity = 40; update oli; // Get updated quantity of inverters OpportunityLineItem updatedInverter = [ SELECT Quantity FROM OpportunityLineItem WHERE OpportunityId = :oli.OpportunityId AND Id = :oli2.Id LIMIT 1 ]; System.assertEquals(10, updatedInverter.Quantity); } }
I'm not sold on the logic, but basically,
if i'm inserting a Panel OLI go find any Invertor OLIs and update that number.
if i'm inserting an invertor OLI go find any Panel OLIs and cacluclate my number I also updated part of your test class - not sure why you were playing with PriceBookEntry in the OLI.
Note that it passes the insert test as well.
Regards
Andrew
All Answers
Your trigger is before update. The code will not run to update the invertor numbers on insert, hence it will fail there
Regards
Andrew
note: you do have a SELECT statement in a FOR loop, bit of a no-no.
Thank you Andrew. There is another trigger that handles the insert logic so that seems to work. I have deleted that assertion anyway now, and it still seems to fail. The error that I get says, "Assertion Failed: Expected: 10, Actual: 5.00".
Also, do you have any suggestions as to how I can move that SOQL query outside of the for loop? The only reason I have it in there is because i needed to reference a bind variable:
Thanks again for your help. I'm very new to this so I appreciate you steering me in the right direction.Before I bend my mind to this, a question - is this code a learning aspect only or are you planning to release this code into a production environment?
The reason I ask is that there are a heap of variables to be considered:.
1. Will panels always be inserted first?
2. Will you have oppty where there are more than the one type of panel or invertor?
3. Will more than one oppty line item contain the same product?
that's the ones that jump out.
Depending on your answer, it will drive how I would create the trigger. And therefore the complexity and time it takes. And noting the complexity I would then go to a trigger with a trigger handler.
Regards
Andrew
It is a before insert , so therefore the record being updated does not exist in the database, and therefore the query is querying the records as they exist "now" in the database. So when you query the database, the quantity is 20. And that is the value that you use in the calculation as opposed to the value in the now being updated records.
You could test this by doing a simple change And as an aside, I would do that entire section as: the change is the divisor only - the rest of the logic remains the same, so why not create a variable for the divisor and write the other lines once?
Regards
Andrew
Regards
Andrew
Hey Andrew, thank you for the code revision. The divisor logic makes perfects sense and I'll be trying it out soon. Also, yes I am planning on releasing this code into a production environment (first time doing so if you couldn't already tell...). It is a brand new instance as we are just starting.
Here's some answers to your questions:
1. Will panels always be inserted first?
I was hoping to get this to work two ways. First, if panels have been already inserted. And second, if panels and inverters are inserted at the same time. I don't see a situation where inverters will be inserted first.
2. Will you have oppty where there are more than the one type of panel or invertor?
No, every opportunity will have one type of panel and one type inverter.
3. Will more than one oppty line item contain the same product?
I would say no for now.
I'm not sold on the logic, but basically,
if i'm inserting a Panel OLI go find any Invertor OLIs and update that number.
if i'm inserting an invertor OLI go find any Panel OLIs and cacluclate my number I also updated part of your test class - not sure why you were playing with PriceBookEntry in the OLI.
Note that it passes the insert test as well.
Regards
Andrew
Andrew, you have been an absolute lifesaver. I can't thank you enough. The trigger and test class check out on my end. I'm gonna have to read through the code a few more times so I can understand how it's working and learn from my past mistakes. As for your comment about the Pricebook entry in the OLI, I simply must have thought it was a required field. But everything seems to be working fine without it, so clearly I was mistaken.
Next thing for you to play with is creating a Handler class, which I would recommend. I generally keep my triggers as simple as possible and do the work with handlers.
Here's an example I did on another post that may prove helpful
https://developer.salesforce.com/forums/ForumsMain?id=9062I000000IK8dQAG
Have fun
Regards
Andrew