0

There might be a lot of other ways to achieve what I am trying to do here but for practice I am using trigger.

The trigger is to update a field acc_number__c in contact if the finalize_number__c field is checked. the value is update from a account field also named acc_number__c.

The trigger worked so now to understand class testing this is what I did. but the test run fails every time. What am I doing wrong?

Error

System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, Accnumberupdate3: execution of BeforeInsert caused by: System.NullPointerException: Attempt to de-reference a null object Class.accnumberupdateclss.replacer: line 17, column 1 Trigger.Accnumberupdate3: line 5, column 1: []

Test Class

@istest
public class Accnumberupdate3test {

    Static testmethod void test(){
        //give in the values
        Contact con = new Contact(LastName='TestRun1', Finalize_Number__c=true);
        System.debug('Acc number before insert : ' + con.acc_number__c);
        // insert the values
        insert con;
        con = [SELECT acc_number__c FROM Contact WHERE Id =:con.Id];
        System.debug('Acc number after insert : ' + con.acc_number__c);
    }
} 

Trigger

trigger Accnumberupdate3 on contact (before insert) {
    // create a new contact object to pass through the class method
    contact[] allconlist = trigger.new;
    //pass it in the method
    accnumberupdateclss.replacer(allconlist);
}

Trigger Handler

public class accnumberupdateclss {

    public static void replacer(contact[] allconlist){

        //get all ids for contacts recieved
        Set <id> ids = new set<id>();
        for( contact c : allconlist){
            ids.add(c.accountId);}
            //get all account ids
            Map<ID, Account> mapacc = new Map<ID, Account>([SELECT acc_number__c,id FROM Account WHERE id IN :ids]);

            for(contact c: allconlist ){
                if(c.Finalize_Number__c == true){ 
                    Account related = new account();
                    related = mapacc.get(c.accountid);
                    c.Acc_Number__c = related.acc_number__c;
                }
            }
        }
    }
}
2

Note: You could just use a formula field......

Looks like an attempt to dereference null object at

related.Acc_number__c

The account map has no values because you never created any accounts. Also need to populate AccountID on the contact.

Even though you set related to a new account you replaced that with null with the map get.

I'll leave the critique of the trigger for another question.

You also need to add some asserts to validate functionality. Without the the test is just a smoke test

Example Test Maybe a bit overkill but wanted to show some simple concepts

@istest
public class Accnumberupdate3test {

    //Get the account created in the tet setup method
    private static Account testAccount = [Select Id, Name, acc_number__c From Account Where Name = 'Test Account'];

    /***************************************************
    * @description Test standard behavior in a poitive use case
    ****************************************************/
    Static testmethod void test(){

        //Create a contact with the values needed to update acc_number__c field
        Contact con = doContactInsert(true,testAccountId,true);

        //Retrieve update values
        con = [SELECT acc_number__c FROM Contact WHERE Id =:con.Id];

        System.assertEquals(testAccount.acc_number__c,con.acc_number__c,'The acc_number field on contact was not updated');
    }

    /***************************************************
    * @description Test behavior in a negative use case
    * No AccountId
    ****************************************************/
    static testmethod void test_with_error(){
        //Create a contact without all the values needed to update acc_number__c field
        Contact con = doContactInsert(true,null,true);

        try {
            insert con;
            system.assertEquals(false, true, 'An error should have been thrown');
        }catch(accnumberupdateclss_exception e){
            System.assertEquals(accnumberupdateclss.NOACCEXCEPTION,e.getMessage(),'The expected error message was not thrown');
        }


    }

    /***************************************************
    * @description Test behavior in a negative use case
    * finalize_number__c = false
    ****************************************************/
    static testmethod void test_finalize_false(){
        //Create a contact with all the values needed to update acc_number__c field but sset Finalize Number to false
        Contact con = doContactInsert(true,testAccountId,false);

        //Retrieve update values
        con = [SELECT acc_number__c FROM Contact WHERE Id =:con.Id];

        System.assertEquals(null,con.acc_number__c,'The acc_number field on contact was updated when finalize number was false');

    }


    /***************************************************
    * @description Helper class since we are creating contacts in every method
    ****************************************************/
    private static Contact doContactInsert(Id AccountId, Boolean finalize, Boolean doInsert){
        Contact con = new Contact(
                LastName='TestRun',
                Finalize_Number__c = finalize,
                AccountId = testAccount.Id
        );

        // insert the values
        if(doInsert == true) insert con;
        return con;

    }

    @TestSetup
    private static void setUpData(){
        Account a = New Account(
                Name = 'Test Account',
                acc_number__c = '1234'
        );
        insert a;
    }
} 

Example Class

public class accnumberupdateclss {

    @testVisible private static final string NOACCEXCEPTION = 'No related account found';

    public static void replacer(contact[] allconlist) {

        Set<id> ids = new set<id>();
        for (contact c : allconlist) {
            ids.add(c.accountId);
        }

        Map<ID, Account> mapacc = new Map<ID, Account>([
                SELECT
                        acc_number__c,
                        id
                FROM Account
                WHERE id IN :ids
        ]);

        for (contact c: allconlist) {
            if (c.Finalize_Number__c == true) {
                if (mapacc.containsKey(c.AccountId) == false) {
                    throw new accnumberupdateclss_exception(NOACCEXCEPTION);
                    //If you do not want to throw an error then you could imply do this
                    //continue; //skip to the next record
                }

                //We already know there is a key of type account so we can simply do this
                c.Acc_Number__c = mapacc.get(c.accountid).acc_number__c;
            }
        }
    }

    public class accnumberupdateclss_exception extends Exception {
    }
}

Note: Basic typos may exit especially since my s key keeps ticking and not working lol

  • Firstly thanks. Yes i wanted to use assert but i wasnt able to figure out how to relate the account field to equate with the contact field so i left it so that i can run this test first and then try assert. umm , Map<ID, Account> mapacc = new Map<ID, Account>([select acc_number__c,id from account where id in :ids]); Does this not do anything?, mapacc is null u mean? does the below work?Set <id> ids = new set<id>(); for( contact c : allconlist){ ids.add(c.accountId);} Thanks again – Niknit May 26 '17 at 13:34
  • @Niknit - You have not created an account so there are no values in the map. When you blindly do a get it returns null. The map itself i not null a the way you are instantiating the map return an empty map when the query returns no results. You would be checking to ensure the map key exits. All no need to do New Account() when declaring related. just use Account related = mapacc.get..... after checking to ensure a key exist. If a key doe not exist move on to the next record or throw an error – Eric May 26 '17 at 13:58
  • Thanks i understand the null part. the problem was i didnt realize it would be null. Doesn't it have access to database ? is this what is said in test class you we need to create data for input? if i had used @istest(seealldata=true), would it had accessed the account data in map? – Niknit May 26 '17 at 14:07
  • @Niknit - Updated with more details in the examples – Eric May 26 '17 at 14:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.