+ Start a Discussion
Olavo ZapataOlavo Zapata 

Error in ApexTest difficulties to upload Trigger to production

Hello guys,

I'm having a hard time with a test to upload a trigger to Production.
Trigger is an autonumber that is executed only when active accounts in the second month receive a trigger to route new user.
Trigger:
trigger AutonumberOnlyISOnb on JBCXM__CustomerInfo__c (before insert, before update){
    list<JBCXM__CustomerInfo__c> l= [SELECT Id,Name,IS_Autonumber__c FROM JBCXM__CustomerInfo__c WHERE IS_Autonumber__c !=:null ORDER BY IS_Autonumber__c DESC LIMIT 1];
    decimal maxacc = l[0].IS_Autonumber__c;
    
    List<JBCXM__CustomerInfo__c> LiList = new List<JBCXM__CustomerInfo__c>();
    for(JBCXM__CustomerInfo__c li:trigger.new) {
        if((li.JBCXM__Status__c == 'a0U1a000000H1GiEAK') &&
            (li.JBCXM__CustomerLifetimeInMonths__c == 2) &&
            (li.RR_Rotear_Adopter__c == true) &&
            (li.IS_Autonumber__c == null)
            ) {
            li.IS_Autonumber__c = Integer.valueOf(maxacc)+1;
        }
        LiList.add(li);
    }
}
The trigger is working perfectly as I expected.
However, due to my low maturity in APEX I couldn't code the test.
Test:
@isTest(OnInstall=true)
private class TestRoterAdopter {
    public static List<JBCXM__CustomerInfo__c> customers;
    static void init(){
	    customers = new List<JBCXM__CustomerInfo__c>();
		customers.add(new JBCXM__CustomerInfo__c(
            JBCXM__Account__c = '0011a00000rDPkpAAG',
            JBCXM__Status__c = 'a0U1a000000H1GiEAK',
			IS_Autonumber__c = 1,
            JBCXM__OriginalContractDate__c = date.newInstance(2018, 05, 20)         
        )); // date with workaround to get lifetime = 2 should be OCD - 2 months.
    }
     
     /** Test with an existing account **/
    static testMethod void TestRoterAdoptertoTrue() {
    init();
    Test.startTest();
	customers.add(new JBCXM__CustomerInfo__c(
            JBCXM__Account__c = '0011a00000rDPkpAAG',
            JBCXM__Status__c = 'a0U1a000000H1GiEAK',
            JBCXM__OriginalContractDate__c = date.newInstance(2018, 05, 20)          
        ));
	    insert customers; 
		
        List<JBCXM__CustomerInfo__c> customerList =
        [SELECT Id,Name,IS_Autonumber__c FROM JBCXM__CustomerInfo__c WHERE 
        IS_Autonumber__c =:null AND 
        JBCXM__Status__c = 'a0U1a000000H1GiEAK' AND
        JBCXM__CustomerLifetimeInMonths__c = 2 AND
        RR_Rotear_Adopter__c = false
        LIMIT 1
        ];
        customerList[0].RR_Rotear_Adopter__c = true; //new value
        
        Test.startTest();
        update customerList[0]; //modificando um registro
        // Verification
        System.assertNotEquals(customerList[0].IS_Autonumber__c, null);
    Test.stopTest();
    }
}

I'm afraid if anyone could help me with this test.
Error:
System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, AutonumberOnlyISOnb: execution of BeforeInsert
caused by: System.ListException: List index out of bounds: 0
Trigger.AutonumberOnlyISOnb: line 3, column 1: []

Class.TestRoterAdopter.TestRoterAdoptertoTrue: line 23, column 1
Thanks
Best Answer chosen by Olavo Zapata
Steven NsubugaSteven Nsubuga
In the WHERE clause you have RR_Rotear_Adopter__c = falseJBCXM__CustomerLifetimeInMonths__c = 2
I am guessing that RR_Rotear_Adopter__c is a checkbox that is by default false, and JBCXM__CustomerLifetimeInMonths__c is a formula field?
Make sure your WHERE clause is working as expected. 

All Answers

Steven NsubugaSteven Nsubuga
It is probably because that you do not do an insert customers in the init method of your test.
Olavo ZapataOlavo Zapata
Hi Steven,

I did. I this code that I copied I moved inside the Test() but I tried to put outside as well. And give me the same error.
Steven NsubugaSteven Nsubuga
Try this
@isTest(OnInstall=true)
private class TestRoterAdopter {
    public static List<JBCXM__CustomerInfo__c> customers;
    static void init(){
	    customers = new List<JBCXM__CustomerInfo__c>();
		customers.add(new JBCXM__CustomerInfo__c(
            JBCXM__Account__c = '0011a00000rDPkpAAG',
            JBCXM__Status__c = 'a0U1a000000H1GiEAK',
			IS_Autonumber__c = 1,
            JBCXM__OriginalContractDate__c = date.newInstance(2018, 05, 20)         
        )); // date with workaround to get lifetime = 2 should be OCD - 2 months.
        insert customers;
    }
     
     /** Test with an existing account **/
    static testMethod void TestRoterAdoptertoTrue() {
    init();
    Test.startTest();
	
		
        List<JBCXM__CustomerInfo__c> customerList =
        [SELECT Id,Name,IS_Autonumber__c FROM JBCXM__CustomerInfo__c WHERE 
        IS_Autonumber__c =:null AND 
        JBCXM__Status__c = 'a0U1a000000H1GiEAK' AND
        JBCXM__CustomerLifetimeInMonths__c = 2 AND
        RR_Rotear_Adopter__c = false
        LIMIT 1
        ];
        customerList[0].RR_Rotear_Adopter__c = true; //new value
        
        update customerList[0]; //modificando um registro
        // Verification
        System.assertNotEquals(customerList[0].IS_Autonumber__c, null);
    Test.stopTest();
    }
}

 
Olavo ZapataOlavo Zapata

Hi Steven,
Doesn't work as well its very tricker 

Look the error:

System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, AutonumberOnlyISOnb: execution of BeforeInsert

caused by: System.ListException: List index out of bounds: 0

Trigger.AutonumberOnlyISOnb: line 3, column 1: []
---
Class.TestRoterAdopter.init: line 12, column 1
Class.TestRoterAdopter.TestRoterAdoptertoTrue: line 17, column 1
I understood when I read this error that I probably wouldn't be able to execute the trigger because in the test environment I wouldn't have an account with the autonumber empty.
So I inserted that record into the test that would be from an account without the autonumber.
The first Customer.add is an account with autonumber for the SELECT to find something.
The second is the account that would test the autonumber generation.
 
Steven NsubugaSteven Nsubuga
I think I see why this is failing!! 
In the first line of your trigger on JBCXM__CustomerInfo__c, you already expect a record of JBCXM__CustomerInfo__c to exist in Salesforce!!
However, you are inserting this first record it in your test, and this causes the trigger to run, expecting that record to already exist!!
Line 3 in the trigger will always return no records in production or any new instance of Salesforce!!!
I suggest you use a different object maybe name it JBCXM__InitCustomerInfo__c, with the very same fields as JBCXM__CustomerInfo__c, to store the initial JBCXM__CustomerInfo__c  record, and insert this new type in your init method. 
Alternatively use a custom metadata type to store the initial values.
 
@isTest(OnInstall=true)
private class TestRoterAdopter {
    static void init(){
    JBCXM__InitCustomerInfo__c initCustomer = new JBCXM__InitCustomerInfo__c(JBCXM__Account__c = 11a00000rDPkpAAG', 
                           JBCXM__Status__c = 'a0U1a000000H1GiEAK',
                           IS_Autonumber__c = 1, 
                           JBCXM__OriginalContractDate__c = date.newInstance(2018, 05, 20)
                           // date with workaround to get lifetime = 2 should be OCD - 2 months.
                           );
     insert initCustomer;
    }

     
     /** Test with an existing account **/
    static testMethod void TestRoterAdoptertoTrue() {
    init();
    Test.startTest();
	customers.add(new JBCXM__CustomerInfo__c(
            JBCXM__Account__c = '0011a00000rDPkpAAG',
            JBCXM__Status__c = 'a0U1a000000H1GiEAK',
            JBCXM__OriginalContractDate__c = date.newInstance(2018, 05, 20)          
        ));
	    insert customers; 
		
        List<JBCXM__CustomerInfo__c> customerList =
        [SELECT Id,Name,IS_Autonumber__c FROM JBCXM__CustomerInfo__c WHERE 
        IS_Autonumber__c =:null AND 
        JBCXM__Status__c = 'a0U1a000000H1GiEAK' AND
        JBCXM__CustomerLifetimeInMonths__c = 2 AND
        RR_Rotear_Adopter__c = false
        LIMIT 1
        ];
        customerList[0].RR_Rotear_Adopter__c = true; //new value
        
        Test.startTest();
        update customerList[0]; //modificando um registro
        // Verification
        System.assertNotEquals(customerList[0].IS_Autonumber__c, null);
    Test.stopTest();
    }
}

Trigger
trigger AutonumberOnlyISOnb on JBCXM__CustomerInfo__c (before insert, before update){

    // Trigger uses new object called JBCXM__InitCustomerInfo__c 
    list<JBCXM__InitCustomerInfo__c> l= [SELECT Id,Name,IS_Autonumber__c FROM JBCXM__InitCustomerInfo__c WHERE IS_Autonumber__c !=:null ORDER BY IS_Autonumber__c DESC LIMIT 1];
    decimal maxacc = l[0].IS_Autonumber__c;
    
    List<JBCXM__CustomerInfo__c> LiList = new List<JBCXM__CustomerInfo__c>();
    for(JBCXM__CustomerInfo__c li:trigger.new) {
        if((li.JBCXM__Status__c == 'a0U1a000000H1GiEAK') &&
            (li.JBCXM__CustomerLifetimeInMonths__c == 2) &&
            (li.RR_Rotear_Adopter__c == true) &&
            (li.IS_Autonumber__c == null)
            ) {
            li.IS_Autonumber__c = Integer.valueOf(maxacc)+1;
        }
        LiList.add(li);
    }
}


 
Glyn Anderson (Slalom)Glyn Anderson (Slalom)
Rather than create a new custom object or custom metadata type, just make the trigger handle the case where there aren't any autonumber records yet:
trigger AutonumberOnlyISOnb on JBCXM__CustomerInfo__c (before insert, before update)
{
    List<JBCXM__CustomerInfo__c> l =
    (   [   SELECT  Id, IS_Autonumber__c
            FROM    JBCXM__CustomerInfo__c
            WHERE   IS_Autonumber__c != null
            ORDER BY IS_Autonumber__c DESC
            LIMIT 1
        ]
    );
    Decimal maxacc = l.isEmpty() ? 0 : l[0].IS_Autonumber__c;

    for ( JBCXM__CustomerInfo__c li : Trigger.new )
    {
        if  (   li.JBCXM__Status__c == 'a0U1a000000H1GiEAK'
            &&  li.JBCXM__CustomerLifetimeInMonths__c == 2
            &&  li.RR_Rotear_Adopter__c
            &&  li.IS_Autonumber__c == null
            )
        {
            li.IS_Autonumber__c = Integer.valueOf( ++maxacc );
        }
    }
}
Note that hard-coding the ID, 'a0U1a000000H1GiEAK', means that this code won't work in any org other than the one it was written in.  If you're deploying this code to a new org, you're going to have to rewrite that part to use an ID value that you have queried.  The will be true of the hard-coded IDs in your test code.
Olavo ZapataOlavo Zapata
Hi guys,
I really appreciate your help. But I a dumb on this I still without understand how to solve the error on Test.
I changed my trigger for the Glyn suggestion and my test is like this:
@isTest(OnInstall=true)
private class TestRoterAdopter {
    public static List<JBCXM__CustomerInfo__c> customers;
    static void init(){
        customers = new List<JBCXM__CustomerInfo__c>();
         // Insert a customer with OCD date with workaround to get lifetime = 2 should be OCD - 2 months.
        customers.add(new JBCXM__CustomerInfo__c(
            JBCXM__Account__c = '0011a00000rDPkpAAG',
            JBCXM__Status__c = 'a0U1a000000H1GiEAK',
            IS_Autonumber__c = 1,
            JBCXM__OriginalContractDate__c = date.newInstance(2018, 06, 20)         
        ));
        insert customers; 
    }
     
     /** Test with an existing account **/
    static testMethod void TestRoterAdoptertoTrue() {
    init();
    Test.startTest();
        customers.add(new JBCXM__CustomerInfo__c(
            JBCXM__Account__c = '0011a00000rDPkpAAG',
            JBCXM__Status__c = 'a0U1a000000H1GiEAK',
            JBCXM__OriginalContractDate__c = date.newInstance(2018, 06, 20)          
        ));
        upsert customers;

        List<JBCXM__CustomerInfo__c> customerList =
        [SELECT Id,IS_Autonumber__c FROM JBCXM__CustomerInfo__c WHERE 
        IS_Autonumber__c =:null AND 
        JBCXM__Status__c = 'a0U1a000000H1GiEAK' AND
        JBCXM__CustomerLifetimeInMonths__c = 2 AND
        RR_Rotear_Adopter__c = false
        LIMIT 1
        ];
        //new value
        if(customerList.size() > 0) {
            customerList[0].RR_Rotear_Adopter__c = true;
        }
        //modifica o registro
            update customerList[0];
        // Verification
        System.assertNotEquals(customerList[0].IS_Autonumber__c, null);
    Test.stopTest();
    }
}
If I keep like that I receive an error of:
System.AssertException: Assertion Failed: Same value: null
Class.TestRoterAdopter.TestRoterAdoptertoTrue: line 42, column 1
I tried to change the line 25 to an insert instead of upsert but get me an error too.
System.DmlException: Insert failed. First exception on row 0 with id a0D0U000000cC4gUAE; first error: INVALID_FIELD_FOR_INSERT_UPDATE, cannot specify Id in an insert call: [Id]
Class.TestRoterAdopter.TestRoterAdoptertoTrue: line 25, column 1
Using an upsert for me shouldn't be right.
I'm afraid if someone can help me to understand what could be. 

Thanks

 
Steven NsubugaSteven Nsubuga
Seems to me that line 27 may not be returning any record. Can you check that a record is being returned in customerList?
Olavo ZapataOlavo Zapata
But I can not understand why.
When I used init and insert customers I wanted to create these records in the test environment.

I see no explanation to not find it =/.
Steven NsubugaSteven Nsubuga
In the WHERE clause you have RR_Rotear_Adopter__c = falseJBCXM__CustomerLifetimeInMonths__c = 2
I am guessing that RR_Rotear_Adopter__c is a checkbox that is by default false, and JBCXM__CustomerLifetimeInMonths__c is a formula field?
Make sure your WHERE clause is working as expected. 
This was selected as the best answer
Olavo ZapataOlavo Zapata
Hi Steven,

Thanks for your help. The problem really was in the Select.
But not in the one that was requested to make the change.
The error happened because the code was trying to assert the Select before the change. So, I made a new select after the update and now it worked.

Thank you.