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
BobBob 

Apex opportunity trigger 0% test coverage

I have a opportunity trigger that I'm trying to move to my production org, but the test class gives me an error message stating there is zero percent coverage. I have the trigger and the test class below. I've looked at the test class and can not figure out why there is'nt enough coverage for the trigger. Any help would be greatly appreciated.

Trigger:
trigger Update_Opportunity_Amount on Quote (before insert, before update) {
List<Opportunity> opps = new List<Opportunity>();
List<Quote> quotes = new List<Quote>();
Map<Id, Double> quoteNR = new Map<Id, Double>();
Set<Id> oppIds = new Set<Id>();
Set<Id> qteIds = new Set<Id>();
for (Quote q : Trigger.new) {
if (q.Primary_Quote__c == true) {
quotes.add(q);
qteIds.add(q.Id);
if (!quoteNr.isEmpty() && quoteNr.containsKey(q.OpportunityId)) {
quoteNR.clear();
q.addError('You are attempting to create multiple Primary Quotes into the one Opportunity');
}
else {
quoteNR.put(q.OpportunityId, q.Net_Revenue__c);
}
}
}
if (!quoteNR.isEmpty()) {
// Check if any Quotes tied to the same Opportunity as this Quote is listed as a Primary Quote
for (Quote q : [SELECT Id, Primary_Quote__c, OpportunityId FROM Quote WHERE OpportunityId IN :quoteNR.keySet() AND Primary_Quote__c = true]) {
if (qteIds.isEmpty() || !qteIds.contains(q.Id)) {
oppIds.add(q.OpportunityId);
}
}
if (!oppIds.isEmpty()) {
for (Quote q : quotes) {
if (oppIds.contains(q.OpportunityId)) {
q.addError('The Opportunity tied to this Quote already contains a Primary Quote. This quote cannot be set as a Primary Quote');
}
}
}
// Update the Opportunity with the Net Revenue from the Quote
for (Opportunity o : [SELECT Id, Amount FROM Opportunity WHERE Id IN :quoteNR.keySet()]) {
o.Amount = quoteNR.get(o.Id);
opps.add(o);
}
}
if (!opps.isEmpty()) {
update(opps);
}
}
@isTest
private class Update_Opportunity_Amount_TestClass {
static testMethod void myUnitTest() {
RecordType naOppType = [SELECT Id FROM RecordType WHERE Name = 'NA Opportunity Record Type' LIMIT 1];
RecordType naAccTypeCustomer = [SELECT Id FROM RecordType WHERE Name = 'NA Customer Account Record Type - Active Customer - BW' LIMIT 1];
RecordType naAccTypeProspect = [SELECT Id FROM RecordType WHERE Name = 'NA Customer Account Record Type - Prospect - BW' LIMIT 1];
List<Account> accs = new List<Account>();
List<Opportunity> opps = new List<Opportunity>();
List<Quote> quotes = new List<Quote>();
// Insert the Accounts to be used for the testing
Integer j = 0;
for (Integer i = 0; i < 41; i++) {
Account a = new Account();
a.Name = 'Account Test ' + i;
a.Sales_Channel__c = '160 SPECIAL FORCES';
a.Marketing_Level__c = 'Developer';
a.Billing_Region__c = '1';
a.BillingCity = '1';
a.BillingCountry = '1';
a.BillingPostalCode = '1';
a.BillingState = '1';
a.BillingStreet = '1';
a.Shipping_Region__c = '1';
a.ShippingCity = '1';
a.ShippingCountry = '1';
a.ShippingPostalCode = '1';
a.ShippingState = '1';
a.ShippingStreet = '1';
if (j == 0) {
a.RecordTypeId = naAccTypeProspect.Id;
j = 1;
}
else {
a.RecordTypeId = naAccTypeCustomer.Id;
j = 0;
}
accs.add(a);
}
insert(accs);
// Insert the Opportunities to be used for the testing
for (Integer i = 0; i < 41; i++) {
Opportunity o = new Opportunity();
o.Name = 'Opportunity Test ' + i;
o.Amount = 111.11;
o.StageName = 'H - Hot Prospect';
o.CloseDate = Date.today() + 365;
o.AccountId = accs[i].Id;
o.RecordTypeId = naOppType.Id;
if (j == 0) {
o.Interface_Status_del__c = 'D';
j = 1;
}
else {
j = 0;
}
opps.add(o);
}
insert(opps);
// Create Quoets that are NOT Primary Quotes. Each Quote for its own Opportunity
for (Integer i = 0; i < 40; i++) {
Quote q = new Quote();
q.Name = 'Quote Test ' + i;
q.Net_Revenue__c = 222.22;
q.Primary_Quote__c = false;
q.OpportunityId = opps[i].Id;
quotes.add(q);
}
insert(quotes);
// Validate that the Amount on the Opportunities still equals 111.11
for (Opportunity o : [SELECT Id, Amount FROM Opportunity WHERE Id IN :opps AND Id != :opps[40].Id]) {
System.assertEquals(o.Amount, 222.22);
}
// Create Quoets that are Primary Quotes. Each Quote for its own Opportunity
quotes.clear();
for (Integer i = 0; i < 40; i++) {
Quote q = new Quote();
q.Name = 'Quote Test ' + i;
q.Net_Revenue__c = 999.99;
q.Primary_Quote__c = true;
q.OpportunityId = opps[i].Id;
quotes.add(q);
}
insert(quotes);
// Validate that the Amount on the Opportunities now equals 999.99
for (Opportunity o : [SELECT Id, Amount FROM Opportunity WHERE Id IN :opps AND Id != :opps[40].Id]) {
System.assertEquals(o.Amount, 999.99);
}
// Update the Quotes with a new Net Revenue
for (Quote q : quotes) {
q.Net_Revenue__c = 555.55;
}
update(quotes);
// Validate that the Amount on the Opportunities now equals 555.55
for (Opportunity o : [SELECT Id, Amount FROM Opportunity WHERE Id IN :opps AND Id != :opps[40].Id]) {
System.assertEquals(o.Amount, 555.55);
}
// Insert new Quotes that are also Primary Quotes to the same Opportunities as above. An error should be thrown
quotes.clear();
for (Integer i = 0; i < 40; i++) {
Quote q = new Quote();
q.Name = 'Quote Test ' + i;
q.Net_Revenue__c = 333.33;
q.Primary_Quote__c = true;
q.OpportunityId = opps[i].Id;
quotes.add(q);
}
// Validate that the Amount on the Opportunities still equals 555.55 and not 333.33
for (Opportunity o : [SELECT Id, Amount FROM Opportunity WHERE Id IN :opps AND Id != :opps[40].Id]) {
System.assertEquals(o.Amount, 555.55);
}
// Create multiple Quotes for the one Opportunity all quotes being a Primary Quote. An error should be thrown
// Check that the last Opportunity (used for above test) still has the Amount 111.11
for (Opportunity o : [SELECT Id, Amount FROM Opportunity WHERE Id = :opps[40].Id]) {
System.assertEquals(o.Amount, 111.11);
}
}
}
Test Class:
@isTest
private class Update_Opportunity_Amount_TestClass {

    









static testMethod void myUnitTest() {
        
        RecordType naOppType = [SELECT Id FROM RecordType WHERE Name = 'NA Opportunity Record Type' LIMIT 1];
        RecordType naAccTypeCustomer = [SELECT Id FROM RecordType WHERE Name = 'NA Customer Account Record Type - Active Customer - BW' LIMIT 1];
        RecordType naAccTypeProspect = [SELECT Id FROM RecordType WHERE Name = 'NA Customer Account Record Type - Prospect - BW' LIMIT 1];
        List<Account> accs = new List<Account>();
        List<Opportunity> opps = new List<Opportunity>();
        List<Quote> quotes = new List<Quote>();

        // Insert the Accounts to be used for the testing
        Integer j = 0;
        for (Integer i = 0; i < 41; i++) {
            Account a = new Account();
            a.Name = 'Account Test ' + i;
            a.Sales_Channel__c = '160 SPECIAL FORCES';
            a.Marketing_Level__c = 'Developer';
            a.Billing_Region__c = '1';
            a.BillingCity = '1';
            a.BillingCountry = '1';
            a.BillingPostalCode = '1';
            a.BillingState = '1';
            a.BillingStreet = '1';
            a.Shipping_Region__c = '1';
            a.ShippingCity = '1';
            a.ShippingCountry = '1';
            a.ShippingPostalCode = '1';
            a.ShippingState = '1';
            a.ShippingStreet = '1';
            if (j == 0) {
                a.RecordTypeId = naAccTypeProspect.Id;
                j = 1;
            }
            else {
                a.RecordTypeId = naAccTypeCustomer.Id;
                j = 0;          
            }
            accs.add(a);
        }
        insert(accs);
        
        // Insert the Opportunities to be used for the testing
        for (Integer i = 0; i < 41; i++) {
            Opportunity o = new Opportunity();
            o.Name = 'Opportunity Test ' + i;
            o.Amount = 111.11;
            o.StageName = 'H - Hot Prospect';
            o.CloseDate = Date.today() + 365;
            o.AccountId = accs[i].Id;
            o.RecordTypeId = naOppType.Id;
            if (j == 0) {
                o.Interface_Status_del__c = 'D';
                j = 1;
            }
            else {
                j = 0;          
            }           
            opps.add(o);
        }
        insert(opps);
        
        // Create Quoets that are NOT Primary Quotes. Each Quote for its own Opportunity
        for (Integer i = 0; i < 40; i++) {
            Quote q = new Quote();
            q.Name = 'Quote Test ' + i;
            q.Net_Revenue__c = 222.22;
            q.Primary_Quote__c = false;
            q.OpportunityId = opps[i].Id;
            quotes.add(q);
        }
        insert(quotes);
        
        // Validate that the Amount on the Opportunities still equals 111.11
        for (Opportunity o : [SELECT Id, Amount FROM Opportunity WHERE Id IN :opps AND Id != :opps[40].Id]) {
            System.assertEquals(o.Amount, 222.22);
        }
        
        // Create Quoets that are Primary Quotes. Each Quote for its own Opportunity
        quotes.clear(); 
        for (Integer i = 0; i < 40; i++) {
            Quote q = new Quote();
            q.Name = 'Quote Test ' + i;
            q.Net_Revenue__c = 999.99;
            q.Primary_Quote__c = true;
            q.OpportunityId = opps[i].Id;
            quotes.add(q);
        }
        insert(quotes);
        
        // Validate that the Amount on the Opportunities now equals 999.99
        for (Opportunity o : [SELECT Id, Amount FROM Opportunity WHERE Id IN :opps AND Id != :opps[40].Id]) {
            System.assertEquals(o.Amount, 999.99);
        }       
        
        // Update the Quotes with a new Net Revenue
        for (Quote q : quotes) {
            q.Net_Revenue__c = 555.55;
        }
        update(quotes);     
        
        // Validate that the Amount on the Opportunities now equals 555.55
        for (Opportunity o : [SELECT Id, Amount FROM Opportunity WHERE Id IN :opps AND Id != :opps[40].Id]) {
            System.assertEquals(o.Amount, 555.55);
        }       
        
        
        // Insert new Quotes that are also Primary Quotes to the same Opportunities as above. An error should be thrown
        quotes.clear();     
        for (Integer i = 0; i < 40; i++) {
            Quote q = new Quote();
            q.Name = 'Quote Test ' + i;
            q.Net_Revenue__c = 333.33;
            q.Primary_Quote__c = true;
            q.OpportunityId = opps[i].Id;
            quotes.add(q);
        }
             
        
        // Validate that the Amount on the Opportunities still equals 555.55 and not 333.33 
        for (Opportunity o : [SELECT Id, Amount FROM Opportunity WHERE Id IN :opps AND Id != :opps[40].Id]) {
            System.assertEquals(o.Amount, 555.55);
        }
        
        // Create multiple Quotes for the one Opportunity all quotes being a Primary Quote. An error should be thrown
       
        // Check that the last Opportunity (used for above test) still has the Amount 111.11
        for (Opportunity o : [SELECT Id, Amount FROM Opportunity WHERE Id = :opps[40].Id]) {
            System.assertEquals(o.Amount, 111.11);
        }
    }
}


Lines not covered


 
Andrew RoweAndrew Rowe

Hi Bob,

I have a few triggers that I wrote & to me, writing the test class was harder than writing the trigger itself.  I have one that I'll be posting (that I need help on too).  I'm not an APEX guru, but I've learned to use some of the simple tools in the system to guide me on incrementally building the test class.  In the Developer console, open the test class and the trigger in 2 separate tabs.  Next, do a Test run and select that test class (and all test methods).  Run it.  After it finishes, switch over to the tab with the trigger on it and select the Code Coverage button (it will probably say "None").  When the dropdown appears, you'll see a line with the test class & a percentage next to it.  Click that & the console will highlight your code for the lines that are covered.  In mine, they highlight blue.  The non-covered lines are red.  From there, I look to add lines into my test class (or restructure it) so that those non-covered lines are activated by a test.  I know it sounds simplistic, but that's what's been working for me.  Now, with your code...I would think putting some system debug lines after each of the elements that are created (and before they are to be used) in the trigger would give you insights as to what's missing.  After my reading on my issues, I've seen that 0% ususally means there's an error in the code when the test class runs the data through it.  Finding where the error is can be discovered this way.

I'm sorry I couldn't help with the actual analysis of the code...but just some insights on solution strategies.

Amit Chaudhary 8Amit Chaudhary 8
I hope you are deploying Test class with trigger in production ?